Устанавливаем необходимые библиотки

library(tidyverse)
library(DESeq2)
library(pheatmap)
library(RColorBrewer)
library(clusterProfiler)
library(biomaRt)
library(org.Hs.eg.db)
library(EnhancedVolcano)
library(GenomicRanges)
library(msigdbr)
library(multiMiR)
library(miRBaseConverter)
library(enrichplot)
library(vsn)
library(rvest)
library(patchwork)
library(dbplyr)

Импортируем данные

setwd("/Users/dariakilina/GitHub/Micro-RNA_cardiology")
coldata <- read_tsv("data/phenotableV.tsv", show_col_types = FALSE)
coldata$type <- as.factor(coldata$type)
coldata$patient <- as.factor(coldata$patient)
coldata$condition <- as.factor(coldata$condition)
coldata <- as.data.frame(coldata)
rownames(coldata) <- coldata$sample
coldata
counts <- read.csv("data/miR.Counts.csv", header = TRUE, sep = ",")
counts <- column_to_rownames(counts, var = "miRNA")
#counts <- round(counts) # если используем нормализованные данные
head(counts)
colnames(counts) <- gsub("^X", "", colnames(counts))
common_samples <- intersect(colnames(counts), coldata$sample)

counts <- counts[, c(counts$miRNA, common_samples)]  
counts <- counts[, rownames(coldata)] #ранжирую по колонки в counts так же как и названия строк в coldata
head(counts)
anno <- read.csv("data/annotation.report.csv", header = TRUE, sep = ",")
anno$Sample.name.s. <- gsub("-", ".", anno$Sample.name.s.)
anno <- anno[, -c(2:5, 7, 15)]


common_samples <- intersect(anno$Sample.name.s., coldata$sample)

anno <- anno[anno$Sample.name.s. %in% common_samples, ]
anno <- anno[match(rownames(coldata), anno$Sample.name.s.), ] #ранжирую по колонки в counts так же как и названия строк в coldata
anno

Весь датасет

anno_long <- anno %>%
  pivot_longer(cols = -Sample.name.s., names_to = "RNA_Type", values_to = "Count")

plt <- ggplot(anno_long, aes(x = Sample.name.s., y = Count, fill = RNA_Type)) +
  geom_bar(stat = "identity") +
  theme_minimal() +
  labs(x = "Sample", y = "Read Count") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
  scale_fill_brewer(palette = "Set3")  # Красивые цвета

print(plt)
ggsave("./pictures/barplot_alldataset_no_normalised.tiff", plot = plt, width = 8, height = 6, dpi = 300,  bg = "white")

anno_long <- anno %>%
  rowwise() %>%
  mutate(across(-Sample.name.s., ~ . / sum(c_across(-Sample.name.s.)))) %>% 
  ungroup() %>%
  pivot_longer(cols = -Sample.name.s., names_to = "RNA_Type", values_to = "Proportion")

plt <- ggplot(anno_long, aes(x = Sample.name.s., y = Proportion, fill = RNA_Type)) +
  geom_bar(stat = "identity") +
  theme_minimal() +
  labs(x = "Sample", y = "Proportion") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
  scale_fill_brewer(palette = "Set3")

plt
ggsave("./pictures/barplot_alldataset_normalised.tiff", plot = plt, width = 8, height = 6, dpi = 300, bg = "white")

coldata$condition <- relevel(coldata$condition, ref = "before")
modelMatrix <- model.matrix(~type*condition + patient, data = coldata)
modelMatrix
                    (Intercept) type150 conditionafter patient17 patient29 type150:conditionafter
29.1p16_S39_R1_001            1       0              0         0         1                      0
15.1p16_S33_R1_001            1       0              0         0         0                      0
17.1p16_S35_R1_001            1       0              0         1         0                      0
29.1p150_S40_R1_001           1       1              0         0         1                      0
15.1p150_S34_R1_001           1       1              0         0         0                      0
17.1p150_S36_R1_001           1       1              0         1         0                      0
29.7p16_S41_R1_001            1       0              1         0         1                      0
15.7p16_S31_R1_001            1       0              1         0         0                      0
17.7p16_S37_R1_001            1       0              1         1         0                      0
15.7p150_S32_R1_001           1       1              1         0         0                      1
29.7p150_S42_R1_001           1       1              1         0         1                      1
17.7p150_S38_R1_001           1       1              1         1         0                      1
attr(,"assign")
[1] 0 1 2 3 3 4
attr(,"contrasts")
attr(,"contrasts")$type
[1] "contr.treatment"

attr(,"contrasts")$condition
[1] "contr.treatment"

attr(,"contrasts")$patient
[1] "contr.treatment"
dds <- DESeqDataSetFromMatrix(countData = counts, 
                              colData = coldata, 
                              design = ~type*condition + patient)
converting counts to integer mode
dds$condition <- relevel(dds$condition, ref = "before")
dds
class: DESeqDataSet 
dim: 913 12 
metadata(1): version
assays(1): counts
rownames(913): Hsa-Let-7-P1a_3p* Hsa-Let-7-P1a_5p/P2a1_5p/P2a2_5p ... Hsa-Mir-9851_3p Hsa-Mir-9851_5p*
rowData names(0):
colnames(12): 29.1p16_S39_R1_001 15.1p16_S33_R1_001 ... 29.7p150_S42_R1_001 17.7p150_S38_R1_001
colData names(4): sample condition type patient
dim(dds)
[1] 913  12
smallestGroupSize <- 3
keep <- rowSums(counts(dds) >= 10) >= smallestGroupSize
dds <- dds[keep,]
dim(dds)
[1] 292  12

Run Differential Expression Analysis for all dataset

dds <- DESeq(dds, fitType = "parametric")
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
dds
class: DESeqDataSet 
dim: 292 12 
metadata(1): version
assays(4): counts mu H cooks
rownames(292): Hsa-Let-7-P1a_5p/P2a1_5p/P2a2_5p Hsa-Let-7-P1b_5p ... Hsa-Mir-96-P2_5p Hsa-Mir-96-P3_5p
rowData names(38): baseMean baseVar ... deviance maxCooks
colnames(12): 29.1p16_S39_R1_001 15.1p16_S33_R1_001 ... 29.7p150_S42_R1_001 17.7p150_S38_R1_001
colData names(5): sample condition type patient sizeFactor
plotDispEsts(dds)

raw_counts <- counts(dds, normalized = FALSE)
normalized_counts <- counts(dds, normalized = TRUE)

df <- data.frame(
  Sample = rep(colnames(dds), 2),
  Counts = c(colSums(raw_counts), colSums(normalized_counts)),
  Type = rep(c("Raw", "Normalized"), each = ncol(dds))
)

plt <- ggplot(df, aes(x = Sample, y = Counts, fill = Type)) +
  geom_bar(stat = "identity", position = "dodge") +
  theme_minimal() +
  labs(title = "Counts before and after normalization", x = "Sample", y = "Total Counts") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

plt
ggsave("./pictures/Counts before and after normalization.tiff", plot = plt, width = 8, height = 6, dpi = 300, bg = "white")

rlog трансформация

rlt <- rlog(dds)  #rlog Transformation
meanSdPlot(assay(rlt)) 

vsd <- varianceStabilizingTransformation(dds, blind=FALSE) 
meanSdPlot(assay(vsd)) #показывает, как изменяется стандартное отклонение в зависимости от среднего значения экспрессии

PCA plot

pcaData <- plotPCA(rlt, intgroup=c("condition", "type", "patient"), returnData = TRUE)
using ntop=500 top features by variance
percentVar <- round(100 * attr(pcaData, "percentVar"))

pcaData$condition_type <- paste(pcaData$condition, pcaData$type, sep = "_")

ggplot(pcaData, aes(PC1, PC2, shape = patient, color = condition_type)) +
  geom_point(size = 3) +
  xlab(paste0("PC1: ", percentVar[1], "%")) +
  ylab(paste0("PC2: ", percentVar[2], "%")) + 
  coord_fixed() +
  theme_bw() +
  ggtitle("PCA plot for all dataset before removing donor effect")+
  scale_color_brewer(palette = "Set2")

assay(rlt) <- limma::removeBatchEffect(assay(rlt),
                                       batch = colData(dds)[,'patient'])

pcaData <- plotPCA(rlt, intgroup=c("condition", "type", "patient"), returnData = TRUE)
using ntop=500 top features by variance
percentVar <- round(100 * attr(pcaData, "percentVar"))

pcaData$condition_type <- paste(pcaData$condition, pcaData$type, sep = "_")

plt <- ggplot(pcaData, aes(PC1, PC2, shape = patient, color = condition_type)) +
  geom_point(size = 3) +
  xlab(paste0("PC1: ", percentVar[1], "%")) +
  ylab(paste0("PC2: ", percentVar[2], "%")) + 
  coord_fixed() +
  theme_bw() +
  scale_color_brewer(palette = "Set2")

plt
ggsave("./pictures/PCA plot for all dataset after removing donor effect.tiff", plot = plt, width = 8, height = 6, dpi = 300, bg = "white")

Plot a heatmap of 50 most expressed genes Этот heatmap отражает уровни экспрессии генов, а не разницу между группами. Цвета не означают up- или down-регуляцию в сравнении с контрольной группой, потому что heatmap показывает абсолютные значения экспрессии, а не fold change!

select <- order(rowMeans(counts(dds,normalized=TRUE)),
                decreasing=TRUE)[1:50]
df <- as.data.frame(colData(dds)[,c("type", "condition")])

plt <- pheatmap(assay(rlt)[select,], 
         cluster_rows = TRUE, 
         show_rownames = TRUE, 
         cluster_cols = TRUE, 
         annotation_col = df,
         fontsize_row = 6) 

plt

ggsave("./pictures/Plot a heatmap of 50 most expressed genes.tiff", plot = plt, width = 8, height = 6, dpi = 300, bg = "white")

Plot of the distance between samples heatmap Расчет расстояний между образцами • Обычно используется евклидово расстояние (по умолчанию в DESeq2). • Оно вычисляется по нормализованным данным экспрессии (rlog() или vst()). • Чем меньше расстояние — тем более похожи образцы.

sampleDists <- dist(t(assay(rlt)))
sampleDistMatrix <- as.matrix(sampleDists)
rownames(sampleDistMatrix) <- paste(rlt$condition, rlt$type, sep="_type")
colnames(sampleDistMatrix) <- paste(rlt$condition, rlt$type, sep="_type")
colors <- colorRampPalette(rev(brewer.pal(9, "Blues")) )(255)

plt <- pheatmap(sampleDistMatrix,
         clustering_distance_rows = "euclidean",
         clustering_distance_cols = "euclidean",
         color = colors)

plt

ggsave("./pictures/Plot of the distance between samples heatmap.tiff", plot = plt, width = 8, height = 6, dpi = 300, bg = "white")

Только везикулы типа 150

coldata_150 <- coldata[coldata$type == 150, ]
rownames(coldata_150) <- coldata_150$sample
coldata_150
common_samples_150 <- intersect(colnames(counts), coldata_150$samples)

counts_150 <- counts[, c(counts$miRNA, common_samples)]  
counts_150 <- counts_150[, rownames(coldata_150)] #ранжирую по колонки в counts так же как и названия строк в coldata_150
head(counts_150)
coldata_150$condition <- relevel(factor(coldata_150$condition), ref = "before")
modelMatrix <- model.matrix(~ 0 + patient + condition , coldata)
modelMatrix
                    patient15 patient17 patient29 conditionafter
29.1p16_S39_R1_001          0         0         1              0
15.1p16_S33_R1_001          1         0         0              0
17.1p16_S35_R1_001          0         1         0              0
29.1p150_S40_R1_001         0         0         1              0
15.1p150_S34_R1_001         1         0         0              0
17.1p150_S36_R1_001         0         1         0              0
29.7p16_S41_R1_001          0         0         1              1
15.7p16_S31_R1_001          1         0         0              1
17.7p16_S37_R1_001          0         1         0              1
15.7p150_S32_R1_001         1         0         0              1
29.7p150_S42_R1_001         0         0         1              1
17.7p150_S38_R1_001         0         1         0              1
attr(,"assign")
[1] 1 1 1 2
attr(,"contrasts")
attr(,"contrasts")$patient
[1] "contr.treatment"

attr(,"contrasts")$condition
[1] "contr.treatment"

Создаем DESeqDataSet из матрицы каунтов

dds_150 <- DESeqDataSetFromMatrix(countData = counts_150, 
                              colData = coldata_150, 
                              design = ~ 0 + patient + condition)
converting counts to integer mode
dds_150$condition <- relevel(dds_150$condition, ref = "before")
dds_150
class: DESeqDataSet 
dim: 913 6 
metadata(1): version
assays(1): counts
rownames(913): Hsa-Let-7-P1a_3p* Hsa-Let-7-P1a_5p/P2a1_5p/P2a2_5p ... Hsa-Mir-9851_3p Hsa-Mir-9851_5p*
rowData names(0):
colnames(6): 29.1p150_S40_R1_001 15.1p150_S34_R1_001 ... 29.7p150_S42_R1_001 17.7p150_S38_R1_001
colData names(4): sample condition type patient

Фильтрация

dim(dds_150)
[1] 913   6
smallestGroupSize <- 3
keep <- rowSums(counts(dds_150) >= 10) >= smallestGroupSize
dds_150 <- dds_150[keep,]
dim(dds_150)
[1] 240   6

Run Differential Expression Analysis for 150 type

dds_150 <- DESeq(dds_150, fitType = "parametric")
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
plotDispEsts(dds_150)

res_150 <- results(dds_150, contrast=c("condition", "before", "after"))
res_150
log2 fold change (MLE): condition before vs after 
Wald test p-value: condition before vs after 
DataFrame with 240 rows and 6 columns
                                   baseMean log2FoldChange     lfcSE      stat    pvalue      padj
                                  <numeric>      <numeric> <numeric> <numeric> <numeric> <numeric>
Hsa-Let-7-P1a_5p/P2a1_5p/P2a2_5p  9637.8166      0.3135594  0.384984  0.814474 0.4153737  0.951261
Hsa-Let-7-P1b_5p                   578.3774      0.7372962  0.710691  1.037435 0.2995332  0.930944
Hsa-Let-7-P1c_5p                   390.5366      1.3620176  0.717510  1.898257 0.0576623  0.494248
Hsa-Let-7-P2a1_3p*                  18.6002      6.0987421  2.681041  2.274766 0.0229200  0.347014
Hsa-Let-7-P2a3_5p                10822.5933      0.0444091  0.395465  0.112296 0.9105888  0.990665
...                                     ...            ...       ...       ...       ...       ...
Hsa-Mir-95-P1_3p                     22.921      -3.512453  2.149234 -1.634281 0.1021999  0.655709
Hsa-Mir-95-P2_3p                    288.942       0.282295  0.789321  0.357643 0.7206107  0.955427
Hsa-Mir-96-P1_5p                    193.937       0.657772  0.815933  0.806159 0.4201511  0.951261
Hsa-Mir-96-P2_5p                   5249.788      -0.405491  0.405309 -1.000450 0.3170930  0.930944
Hsa-Mir-96-P3_5p                    205.622       2.158153  1.010105  2.136563 0.0326336  0.391603

MA plot

Фильтрация точек с низким средним экспрессированием (по baseMean). • Обычно отсекаются baseMean < 1. 2. Определение значимых генов (синие точки): • Используется критерий padj < 0.1 по умолчанию, а не < 0.05!

tiff("./pictures/PlotMA_standart_padj_0.05_type150.tiff", 
     width = 8, height = 6, units = "in", res = 300, bg = "white")
plotMA(res_150, alpha = 0.05, ylim = c(-8, 8)) 
dev.off()
null device 
          1 
plotMA(res_150, alpha = 0.05, ylim = c(-8, 8)) 

Кастомный MA plot по p-value

res_df <- res_150 %>%
  as.data.frame() %>%
  mutate(color = case_when( 
    padj < 0.05  ~ "padj < 0.05",   
    pvalue < 0.05  ~ "pvalue < 0.05", 
    TRUE ~ "All micro-RNA"
  ))

plt <- ggplot(res_df, aes(x = baseMean, y = log2FoldChange, color = color)) +
  geom_point(alpha = 0.7, size = 1) +
  geom_hline(yintercept = 0, linetype = "solid", color = "gray40", size = 1.5) +
  scale_color_manual(values = c("All micro-RNA" = "gray70", 
                                "pvalue < 0.05" = "blue", 
                                "padj < 0.05" = "red")) +
  scale_x_log10(labels = scales::scientific) + 
  theme_minimal() +
  labs(x = "mean of normalized counts", 
       y = "log fold change", 
       color = NULL)  # Название легенды

plt
ggsave("./pictures/Сustom MAplot_type150.tiff", plot = plt, width = 8, height = 6, dpi = 300, bg = "white")

Значимые результаты

signres_150 <- results(dds_150, contrast=c("condition", "before", "after"), alpha=0.05) 
summary(signres_150)

out of 240 with nonzero total read count
adjusted p-value < 0.05
LFC > 0 (up)       : 1, 0.42%
LFC < 0 (down)     : 3, 1.2%
outliers [1]       : 0, 0%
low counts [2]     : 0, 0%
(mean count < 6)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results

Let’s arranged it by log2FoldChange:

order_indices <- order(-res_150$log2FoldChange)
res_150[order_indices, ]
log2 fold change (MLE): condition before vs after 
Wald test p-value: condition before vs after 
DataFrame with 240 rows and 6 columns
                               baseMean log2FoldChange     lfcSE      stat      pvalue        padj
                              <numeric>      <numeric> <numeric> <numeric>   <numeric>   <numeric>
Hsa-Mir-150_3p*                 41.0827        6.48415   2.05853   3.14990 0.001633280  0.07839744
Hsa-Mir-328_3p                  92.7095        6.41844   1.64997   3.89004 0.000100228  0.00801828
Hsa-Mir-145_3p*                 44.0673        6.31701   2.05972   3.06693 0.002162671  0.08086155
Hsa-Let-7-P2a1_3p*              18.6002        6.09874   2.68104   2.27477 0.022919964  0.34701443
Hsa-Mir-33-P2_5p*               17.7651        6.08611   2.76046   2.20475 0.027471976  0.34701443
...                                 ...            ...       ...       ...         ...         ...
Hsa-Mir-133-P1_3p/P2_3p/P3_3p  778.6034       -4.27149  0.634382  -6.73331 1.65852e-11 1.99022e-09
Hsa-Mir-431_5p                  18.5437       -4.69940  2.595322  -1.81072 7.01841e-02 5.80834e-01
Hsa-Mir-219-P1_5p*              11.4359       -4.76811  3.574814  -1.33381 1.82267e-01 8.27845e-01
Hsa-Mir-499_5p                  68.1969       -5.58010  1.488728  -3.74824 1.78082e-04 1.06849e-02
Hsa-Mir-208-P2_3p              544.5306       -7.31750  1.032542  -7.08688 1.37167e-12 3.29202e-10

Visualisation for the first gene

#plotCounts(dds_150, gene=which.max(res_150$log2FoldChange), intgroup="condition")
plotCounts(dds_150, gene=which.min(res_150$padj), intgroup="condition")

#plotCounts(dds, gene=rownames(res)[which.min(res$padj[which.max(res$log2FoldChange)])], intgroup="condition")

Volcano plot

plt <- EnhancedVolcano(res_150,
                lab = rownames(res_150),
                x = "log2FoldChange",
                y = "padj",
                pCutoff = 0.05,
                FCcutoff = 1,
                labSize = 3.0,
                boxedLabels = FALSE,
                col = c('black', '#CBD5E8', '#B3E2CD', '#FDCDAC'),
                colAlpha = 1,
                title = NULL,        
                subtitle = NULL) 

plt
ggsave("./pictures/Volcano plot_150type.tiff", plot = plt, width = 8, height = 6, dpi = 300, bg = "white")

rlog трансформация • Черные точки – стандартное отклонение отдельных генов. • Красная линия – сглаженный тренд зависимости SD от среднего значения экспрессии. • Если красная линия наклонена вверх → стандартное отклонение растёт с увеличением среднего (плохая нормализация). • Если красная линия примерно горизонтальна → нормализация сработала хорошо.

rlt_150 <- rlog(dds_150) 
meanSdPlot(assay(rlt_150))  #показывает, как изменяется стандартное отклонение в зависимости от среднего значения экспрессии.

PCA plot PCA – это метод снижения размерности, который показывает различия между образцами. Строится на основе различий в экспрессии по всем генам, даже если они не являются значимо дифференциально экспрессированными. • Оно не накладывает статистических порогов вроде padj < 0.05 или |log2FoldChange| > 1, а просто ищет наибольшие источники вариабельности среди всех измерений. • Поэтому даже небольшие изменения экспрессии могут формировать кластеры и различать группы в PCA, если эти изменения систематичны между образцами.

pcaData <- plotPCA(rlt_150, intgroup=c("condition", "patient"), returnData = TRUE)
using ntop=500 top features by variance
percentVar <- round(100 * attr(pcaData, "percentVar"))

ggplot(pcaData, aes(PC1, PC2, shape = patient, color = condition)) +
  geom_point(size = 3) +
  xlab(paste0("PC1: ", percentVar[1], "%")) +
  ylab(paste0("PC2: ", percentVar[2], "%")) + 
  coord_fixed() +
  theme_bw() +
  scale_color_brewer(palette = "Set2")

assay(rlt_150) <- limma::removeBatchEffect(assay(rlt_150),
                                       batch = colData(dds_150)[,'patient'])

pcaData <- plotPCA(rlt_150, intgroup=c("condition", "patient"), returnData = TRUE)
using ntop=500 top features by variance
percentVar <- round(100 * attr(pcaData, "percentVar"))

plt <- ggplot(pcaData, aes(PC1, PC2, shape = patient, color = condition)) +
  geom_point(size = 3) +
  xlab(paste0("PC1: ", percentVar[1], "%")) +
  ylab(paste0("PC2: ", percentVar[2], "%")) + 
  coord_fixed() +
  theme_bw() +
  scale_color_brewer(palette = "Set2")
plt
ggsave("./pictures/PCA plot for type 150 after removing donor effect.tiff", plot = plt, width = 8, height = 6, dpi = 300, bg = "white")

Plot a heatmap of diff expressed genes

res_sign_150 <- subset(res_150, padj < 0.05 & !is.na(padj) & abs(log2FoldChange) > 1.0)
res_sign_150 <- res_sign_150[order(res_sign_150$log2FoldChange, decreasing = TRUE), ]

sig_genes <- rownames(res_sign_150)  # Получаем имена генов, которые прошли фильтрацию

de_mat <- assay(rlt_150)[sig_genes, ] 
datamatrix <- de_mat

annotation_col <- data.frame(condition = coldata_150$condition)
rownames(annotation_col) <- colnames(datamatrix)

annotation_colors <- list(
  condition = c("before" = "#FFCC00", "after" = "#3399FF")
)

plt <- pheatmap(datamatrix, 
         cluster_rows = TRUE, 
         show_rownames = TRUE, 
         cluster_cols = TRUE, 
         annotation_col = annotation_col,
         annotation_colors = annotation_colors,
         display_numbers = TRUE,
         legend = TRUE,
         fontsize = 15)  
plt

ggsave("./pictures/Heatmap of diff expressed genes_type150.tiff", plot = plt, width = 8, height = 6, dpi = 300, bg = "white")

Plot of the distance between samples heatmap Расчет расстояний между образцами • Обычно используется евклидово расстояние (по умолчанию в DESeq2). • Оно вычисляется по нормализованным данным экспрессии (rlog() или vst()). • Чем меньше расстояние — тем более похожи образцы.

sampleDists_150 <- dist(t(assay(rlt_150)))
sampleDistMatrix_150 <- as.matrix(sampleDists_150)
rownames(sampleDistMatrix_150) <- paste(rlt_150$condition, rlt_150$patient, sep="_patient")
colnames(sampleDistMatrix_150) <- paste(rlt_150$condition, rlt_150$patient, sep="_patient")
colors <- colorRampPalette(rev(brewer.pal(9, "Blues")) )(255)

plt <- pheatmap(sampleDistMatrix_150,
         clustering_distance_rows = "euclidean",
         clustering_distance_cols = "euclidean",
         fontsize = 12,
         legend = FALSE,
         display_numbers = TRUE,
         color = colors)
plt

ggsave("./pictures/Plot of the distance between samples_type150.tiff", plot = plt, width = 8, height = 6, dpi = 300, bg = "white")

Анализ обогащения для везикул типа 150

up_150 <- res_sign_150 %>% 
  as.data.frame() %>% 
  filter(log2FoldChange > 0)
down_150 <- res_sign_150 %>% 
  as.data.frame() %>% 
  filter(log2FoldChange < 0)
rownames(up_150)
[1] "Hsa-Mir-328_3p"
rownames(down_150)
[1] "Hsa-Mir-133-P1_3p/P2_3p/P3_3p" "Hsa-Mir-499_5p"                "Hsa-Mir-208-P2_3p"            

перевела вручную: https://mirgenedb.org/browse/hsa Hsa-Mir-328 = hsa-mir-328 Eutheria — клада зверей, включающая плацентарных и различные вымершие инфраклассы. Hsa-Mir-133-P1 = hsa-mir-133a-1 Gnathostomata Hsa-Mir-133-P2 = hsa-mir-133b Gnathostomata Hsa-Mir-133-P3 = hsa-mir-133a-2 Gnathostomata есть только hsa-miR-133a-3p Hsa-Mir-499 = hsa-mir-499a Vertebrata Hsa-Mir-208-P2 hsa-mir-208a Vertebrata • miRBase: https://www.mirbase.org/ • MirGeneDB: https://mirgenedb.org/

mirna_names_up <- c("hsa-miR-328-3p")
mirna_names_down <- c("hsa-miR-133a-3p", "hsa-miR-133a-3p", "hsa-miR-208a-3p", "hsa-miR-499a-5p")

Конвертация в MIMATID

converted_mirna_up <- miRNAVersionConvert(mirna_names_up)
converted_mirna_down <- miRNAVersionConvert(mirna_names_down)
converted_mirna_up
converted_mirna_down

Запрос таргетов из базы multiMiR

targets150_down <- unique(get_multimir(org = "hsa", mirna = converted_mirna_up$Accession, table = "validated")@data$target_symbol)
Searching mirecords ...
Searching mirtarbase ...
Searching tarbase ...
targets150_up <- unique(get_multimir(org = "hsa", mirna = converted_mirna_down$Accession, table = "validated")@data$target_symbol)
Searching mirecords ...
Searching mirtarbase ...
Searching tarbase ...
#writeLines(targets_down, "targets_down150_list.txt")
#writeLines(targets_up, "targets_up150_list.txt")

Анализ обогащения, связанный со Biological Processes

# msig_go_bp <- msigdbr(species = "Homo sapiens", category = "C7", subcategory = "IMMUNESIGDB")
# 
# GO_enrich_up150_immum <- enricher(gene = targets150_up, TERM2GENE = msig_go_bp[, c("gs_name", "gene_symbol")])
# GO_enrich_down150_immun <- enricher(gene = targets150_down, TERM2GENE = msig_go_bp[, c("gs_name", "gene_symbol")])

GO_enrich_down150_bp <- enrichGO(
  gene          = targets150_down,  
  OrgDb         = org.Hs.eg.db,
  keyType       = "SYMBOL",
  ont           = "BP", 
  pAdjustMethod = "BH",
  qvalueCutoff  = 0.05
)

GO_enrich_up150_bp <- enrichGO(
  gene          = targets150_up,  
  OrgDb         = org.Hs.eg.db,
  keyType       = "SYMBOL",
  ont           = "BP", 
  pAdjustMethod = "BH",
  qvalueCutoff  = 0.05
)

Визуализация Biological Processes

p1 <- dotplot(GO_enrich_up150_bp, showCategory = 20) + 
  ggtitle("BP for Upregulated Targets in Vesicles 150") + 
  theme(
    plot.title = element_text(size = 12, face = "bold"),
    axis.text.y = element_text(size = 8)
  )

p2 <- dotplot(GO_enrich_down150_bp, showCategory = 20) + 
  ggtitle("BP for Downregulated Targets in Vesicles 150") + 
  theme(
    plot.title = element_text(size = 12, face = "bold"),
    axis.text.y = element_text(size = 8)
  )

p1 + p2

combined_plot <- p1 + p2

ggsave("./pictures/GO_enrichment_dotplot_BP_type150.tiff", plot = combined_plot, width = 16, height = 10, dpi = 300)

GO_enrich_UP150_BP <- enrichplot::pairwise_termsim(GO_enrich_up150_bp, method = "JC")

plt <- emapplot(GO_enrich_UP150_BP, 
         repel = TRUE,
         showCategory = 20) +
  ggtitle("All processes for UPregulated targets for vesicles 150") +
  theme(
    plot.title = element_text(size = 12, face = "bold"),
    axis.text = element_text(size = 3)
    )   

plt

ggsave("./pictures/GO_enrichment_emapplot_BP_up_type150.tiff", plot = plt, width = 16, height = 10, dpi = 300)

GO_enrich_DOWN150_BP <- enrichplot::pairwise_termsim(GO_enrich_down150_bp, method = "JC")

plt <- emapplot(GO_enrich_DOWN150_BP, 
         repel = TRUE,
         showCategory = 20) +
  ggtitle("All processes for DOWNregulated targets for vesicles 150") +
  theme(
    plot.title = element_text(size = 12, face = "bold"),
    axis.text = element_text(size = 3)
    )    

plt

ggsave("./pictures/GO_enrichment_emapplot_BP_down_type150.tiff", plot = plt, width = 16, height = 10, dpi = 300)

GO Enrichment of Cellular Component

# msig_go_bp <- msigdbr(species = "Homo sapiens", category = "C7", subcategory = "IMMUNESIGDB")
# 
# GO_enrich_up150_immum <- enricher(gene = targets150_up, TERM2GENE = msig_go_bp[, c("gs_name", "gene_symbol")])
# GO_enrich_down150_immun <- enricher(gene = targets150_down, TERM2GENE = msig_go_bp[, c("gs_name", "gene_symbol")])

GO_enrich_down150_CC <- enrichGO(
  gene          = targets150_down,  
  OrgDb         = org.Hs.eg.db,
  keyType       = "SYMBOL",
  ont           = "CC", 
  pAdjustMethod = "BH",
  qvalueCutoff  = 0.05
)

GO_enrich_up150_CC <- enrichGO(
  gene          = targets150_up,  
  OrgDb         = org.Hs.eg.db,
  keyType       = "SYMBOL",
  ont           = "CC", 
  pAdjustMethod = "BH",
  qvalueCutoff  = 0.05
)
p1 <- dotplot(GO_enrich_up150_CC, showCategory = 20) + 
  ggtitle("GO Enrichment of Cellular Component for Upregulated Targets in Vesicles 150") + 
  theme(
    plot.title = element_text(size = 12, face = "bold"),
    axis.text.y = element_text(size = 12)
  )

p2 <- dotplot(GO_enrich_down150_CC, showCategory = 20) + 
  ggtitle("GO Enrichment of Cellular Component for Downregulated Targets in Vesicles 150") + 
  theme(
    plot.title = element_text(size = 12, face = "bold"),
    axis.text.y = element_text(size = 12)
  )

p1 + p2

combined_plot <- p1 + p2

ggsave("./pictures/GO_enrichment_dotplot_CC_type150.tiff", plot = combined_plot, width = 16, height = 10, dpi = 300)

GO_enrich_UP150_CC <- enrichplot::pairwise_termsim(GO_enrich_up150_CC, method = "JC")

plt <- emapplot(GO_enrich_UP150_CC, 
         repel = TRUE,
         showCategory = 20) +
  ggtitle("All processes for UPregulated targets for vesicles 150") +
  theme(
    plot.title = element_text(size = 12, face = "bold"),
    axis.text = element_text(size = 3)
    )   

plt

ggsave("./pictures/GO_enrichment_emapplot_CC_up_type150.tiff", plot = plt, width = 16, height = 10, dpi = 300)

GO_enrich_DOWN150_CC <- enrichplot::pairwise_termsim(GO_enrich_down150_CC, method = "JC")

plt <- emapplot(GO_enrich_DOWN150_CC, 
         repel = TRUE,
         showCategory = 25) +
  ggtitle("All processes for DOWNregulated targets for vesicles 150") +
  theme(
    plot.title = element_text(size = 12, face = "bold"),
    axis.text = element_text(size = 3)
    )    

plt

ggsave("./pictures/GO_enrichment_emapplot_CC_down_type150.tiff", plot = plt, width = 16, height = 10, dpi = 300)

GO Enrichment of Molecular Function

GO_enrich_down150_MF <- enrichGO(
  gene          = targets150_down,  
  OrgDb         = org.Hs.eg.db,
  keyType       = "SYMBOL",
  ont           = "MF", 
  pAdjustMethod = "BH",
  qvalueCutoff  = 0.05
)

GO_enrich_up150_MF <- enrichGO(
  gene          = targets150_up,  
  OrgDb         = org.Hs.eg.db,
  keyType       = "SYMBOL",
  ont           = "MF", 
  pAdjustMethod = "BH",
  qvalueCutoff  = 0.05
)

p1 <- dotplot(GO_enrich_up150_MF, showCategory = 20) + 
  ggtitle("GO Enrichment of Molecular Function for Upregulated Targets in Vesicles 150") + 
  theme(
    plot.title = element_text(size = 12, face = "bold"),
    axis.text.y = element_text(size = 12)
  )

p2 <- dotplot(GO_enrich_down150_MF, showCategory = 20) + 
  ggtitle("GO Enrichment of Molecular Functiont for Downregulated Targets in Vesicles 150") + 
  theme(
    plot.title = element_text(size = 12, face = "bold"),
    axis.text.y = element_text(size = 12)
  )

p1 + p2

combined_plot <- p1 + p2

ggsave("./pictures/GO_enrichment_dotplot_MF_type150.tiff", plot = combined_plot, width = 16, height = 10, dpi = 300)

GO_enrich_UP150_MF <- enrichplot::pairwise_termsim(GO_enrich_up150_MF, method = "JC")

plt <- emapplot(GO_enrich_UP150_MF, 
         repel = TRUE,
         showCategory = 25) +
  ggtitle("Molecular Function processes for UPregulated targets for vesicles 150") +
  theme(
    plot.title = element_text(size = 12, face = "bold"),
    axis.text = element_text(size = 3)
    )   

plt

ggsave("./pictures/GO_enrichment_emapplot_MF_up_type150.tiff", plot = plt, width = 16, height = 10, dpi = 300)

GO_enrich_DOWN150_MF <- enrichplot::pairwise_termsim(GO_enrich_down150_MF, method = "JC")

plt <- emapplot(GO_enrich_DOWN150_MF, 
         repel = TRUE,
         showCategory = 25) +
  ggtitle("Molecular Function processes for DOWNregulated targets for vesicles 150") +
  theme(
    plot.title = element_text(size = 12, face = "bold"),
    axis.text = element_text(size = 3)
    )   

plt

ggsave("./pictures/GO_enrichment_emapplot_MF_down_type150.tiff", plot = plt, width = 16, height = 10, dpi = 300)

Только везикулы типа 16

coldata_16 <- coldata[coldata$type == 16, ]
rownames(coldata_16) <- coldata_16$sample
coldata_16
common_samples_16 <- intersect(colnames(counts), coldata_16$samples)

counts_16 <- counts[, c(counts$miRNA, common_samples)]  
counts_16 <- counts_16[, rownames(coldata_16)] #ранжирую по колонки в counts так же как и названия строк в coldata_150
head(counts_16)

Создаем DESeqDataSet из матрицы каунтов

dds_16 <- DESeqDataSetFromMatrix(countData = counts_16, 
                              colData = coldata_16, 
                              design = ~ 0 + patient + condition)
converting counts to integer mode
dds_16$condition <- relevel(dds_16$condition, ref = "before")
dds_16
class: DESeqDataSet 
dim: 913 6 
metadata(1): version
assays(1): counts
rownames(913): Hsa-Let-7-P1a_3p* Hsa-Let-7-P1a_5p/P2a1_5p/P2a2_5p ... Hsa-Mir-9851_3p Hsa-Mir-9851_5p*
rowData names(0):
colnames(6): 29.1p16_S39_R1_001 15.1p16_S33_R1_001 ... 15.7p16_S31_R1_001 17.7p16_S37_R1_001
colData names(4): sample condition type patient

Фильтрация

dim(dds_16)
[1] 913   6
smallestGroupSize <- 3
keep <- rowSums(counts(dds_16) >= 10) >= smallestGroupSize
dds_16 <- dds_16[keep,]
dim(dds_16)
[1] 219   6

Run Differential Expression Analysis for 150 type

dds_16 <- DESeq(dds_16, fitType = "parametric")
estimating size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
plotDispEsts(dds_16)

res_16 <- results(dds_16, contrast=c("condition", "before", "after"))
res_16
log2 fold change (MLE): condition before vs after 
Wald test p-value: condition before vs after 
DataFrame with 219 rows and 6 columns
                                   baseMean log2FoldChange     lfcSE      stat    pvalue      padj
                                  <numeric>      <numeric> <numeric> <numeric> <numeric> <numeric>
Hsa-Let-7-P1a_5p/P2a1_5p/P2a2_5p 22993.7673      0.1901164  0.224536  0.846707 0.3971586  0.926559
Hsa-Let-7-P1b_5p                  2527.3696      0.4961225  0.280481  1.768830 0.0769222  0.575168
Hsa-Let-7-P1c_5p                   481.2148      0.5330152  0.461003  1.156209 0.2475958  0.860794
Hsa-Let-7-P2a1_3p*                  23.7282      0.4135740  1.966411  0.210319 0.8334185  0.954993
Hsa-Let-7-P2a3_5p                45006.2426     -0.0642043  0.238029 -0.269733 0.7873659  0.940503
...                                     ...            ...       ...       ...       ...       ...
Hsa-Mir-92-P2c_5p*                  25.3899      -0.754468  2.275831 -0.331513 0.7402570  0.931703
Hsa-Mir-95-P2_3p                   193.6126      -0.340069  0.662909 -0.512995 0.6079550  0.926559
Hsa-Mir-96-P1_5p                    14.4204      -4.216533  2.813830 -1.498503 0.1340025  0.764653
Hsa-Mir-96-P2_5p                  4249.9579      -0.537344  0.268063 -2.004539 0.0450123  0.487244
Hsa-Mir-96-P3_5p                   121.7907       0.504262  0.806362  0.625355 0.5317382  0.926559

MA plot

Фильтрация точек с низким средним экспрессированием (по baseMean). • Обычно отсекаются baseMean < 1. 2. Определение значимых генов (синие точки): • Используется критерий padj < 0.1 по умолчанию, а не < 0.05!

tiff("./pictures/PlotMA_standart_padj_0.05_type16.tiff", 
     width = 8, height = 6, units = "in", res = 300, bg = "white")
plotMA(res_16, alpha = 0.05, ylim = c(-8, 8)) 
dev.off()
null device 
          1 
plotMA(res_16, alpha = 0.05, ylim = c(-8, 8)) 

Кастомный MA plot по p-value

res_df <- res_16 %>%
  as.data.frame %>%
  mutate(color = case_when( 
    pvalue < 0.05 & !is.na(pvalue) & abs(log2FoldChange) > 1  ~ "blue",  # Значимые по p-value и диф экспрессированные
    TRUE ~ "gray70"
  ))

plt <- ggplot(res_df, aes(x = baseMean, y = log2FoldChange, color = color)) +
  geom_point(alpha = 0.7, size = 1) +
  geom_hline(yintercept = 0, linetype = "solid", color = "gray40", size = 1.5) +  # Добавляем линию
  scale_color_manual(values = c("gray70" = "gray70", "blue" = "blue")) +
  scale_x_log10(labels = scales::scientific) + 
  theme_minimal() +
  labs(x = "mean of normalized counts", y = "log fold change") +
  theme(legend.position = "none")

plt
ggsave("./pictures/PlotMA_castom_pvalue0.05_type16.tiff", plot = plt, width = 8, height = 6, dpi = 300, bg = "white")

Значимые результаты

summary(results(dds_16, contrast=c("condition", "before", "after"), alpha=0.05))

out of 219 with nonzero total read count
adjusted p-value < 0.05
LFC > 0 (up)       : 0, 0%
LFC < 0 (down)     : 0, 0%
outliers [1]       : 0, 0%
low counts [2]     : 0, 0%
(mean count < 8)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results

Let’s arranged it by log2FoldChange:

order_indices <- order(-res_16$log2FoldChange)
res_16[order_indices, ]
log2 fold change (MLE): condition before vs after 
Wald test p-value: condition before vs after 
DataFrame with 219 rows and 6 columns
                    baseMean log2FoldChange     lfcSE      stat     pvalue      padj
                   <numeric>      <numeric> <numeric> <numeric>  <numeric> <numeric>
Hsa-Mir-185_5p       14.8310        5.85950   2.69426   2.17481 0.02964445  0.487244
Hsa-Mir-136_5p*      13.3826        5.83711   3.16104   1.84658 0.06480773  0.575168
Hsa-Mir-197_3p       45.5597        4.16951   1.59282   2.61769 0.00885267  0.357073
Hsa-Mir-101-P1_5p*   16.5354        4.08972   2.30004   1.77811 0.07538608  0.575168
Hsa-Mir-10-P3a_5p    37.9479        3.82488   1.69051   2.26256 0.02366292  0.487244
...                      ...            ...       ...       ...        ...       ...
Hsa-Mir-154-P17_3p   15.3729       -4.07531   2.60884  -1.56211  0.1182617  0.764653
Hsa-Mir-190-P1_5p    10.5910       -4.10593   3.44201  -1.19289  0.2329137  0.850135
Hsa-Mir-96-P1_5p     14.4204       -4.21653   2.81383  -1.49850  0.1340025  0.764653
Hsa-Mir-128-P1_5p*   15.3208       -4.49032   3.05489  -1.46988  0.1415942  0.764653
Hsa-Mir-197_5p*      17.0795       -5.15605   2.93332  -1.75775  0.0787901  0.575168

Visualisation for the first gene

plotCounts(dds_16, gene=which.max(res_16$log2FoldChange), intgroup="condition")

plotCounts(dds_16, gene=which.min(res_16$pvalue), intgroup="condition")

#plotCounts(dds, gene=rownames(res)[which.min(res$padj[which.max(res$log2FoldChange)])], intgroup="condition")

Volcano plot

plt <- EnhancedVolcano(res_16,
                lab = rownames(res_16),
                x = "log2FoldChange",
                y = "pvalue",
                pCutoff = 0.05,
                FCcutoff = 1,
                labSize = 3.0,
                boxedLabels = FALSE,
                col = c('black', '#CBD5E8', '#B3E2CD', '#FDCDAC'),
                colAlpha = 1,
                title = NULL,        
                subtitle = NULL) 

plt
ggsave("./pictures/Volcano plot_based_on_Pvalue_16type.tiff", plot = plt, width = 8, height = 6, dpi = 300, bg = "white")

rlog трансформация • Черные точки – стандартное отклонение отдельных генов. • Красная линия – сглаженный тренд зависимости SD от среднего значения экспрессии. • Если красная линия наклонена вверх → стандартное отклонение растёт с увеличением среднего (плохая нормализация). • Если красная линия примерно горизонтальна → нормализация сработала хорошо.

rlt_16 <- rlog(dds_16) 
meanSdPlot(assay(rlt_16))  #показывает, как изменяется стандартное отклонение в зависимости от среднего значения экспрессии.

pcaData <- plotPCA(rlt_16, intgroup=c("condition", "patient"), returnData = TRUE)
using ntop=500 top features by variance
percentVar <- round(100 * attr(pcaData, "percentVar"))

ggplot(pcaData, aes(PC1, PC2, shape = patient, color = condition)) +
  geom_point(size = 3) +
  xlab(paste0("PC1: ", percentVar[1], "%")) +
  ylab(paste0("PC2: ", percentVar[2], "%")) + 
  coord_fixed() +
  theme_bw() +
  scale_color_brewer(palette = "Set2")

assay(rlt_16) <- limma::removeBatchEffect(assay(rlt_16),
                                       batch = colData(dds_16)[,'patient'])

pcaData <- plotPCA(rlt_16, intgroup=c("condition", "patient"), returnData = TRUE)
using ntop=500 top features by variance
percentVar <- round(100 * attr(pcaData, "percentVar"))

plt <- ggplot(pcaData, aes(PC1, PC2, shape = patient, color = condition)) +
  geom_point(size = 3) +
  xlab(paste0("PC1: ", percentVar[1], "%")) +
  ylab(paste0("PC2: ", percentVar[2], "%")) + 
  coord_fixed() +
  theme_bw() +
  scale_color_brewer(palette = "Set2")

plt
ggsave("./pictures/PCA plot for type 16 after removing donor effect.tiff", plot = plt, width = 8, height = 6, dpi = 300, bg = "white")

Plot a heatmap of the most expressed genes

res_sign_16 <- subset(res_16, pvalue < 0.05 & !is.na(pvalue) & abs(log2FoldChange) > 1.0)
res_sign_16 <- res_sign_16[order(res_sign_16$log2FoldChange, decreasing = TRUE), ]

sig_genes <- rownames(res_sign_16)  # Получаем имена генов, которые прошли фильтрацию

de_mat <- assay(rlt_16)[sig_genes, ] 
datamatrix <- de_mat
#datamatrix <- t(scale(t(de_mat)))

annotation_col <- data.frame(condition = coldata_16$condition)
rownames(annotation_col) <- colnames(datamatrix)

annotation_colors <- list(
  condition = c("before" = "#FFCC00", "after" = "#3399FF")
)

plt <- pheatmap(datamatrix, 
         cluster_rows = TRUE, 
         show_rownames = TRUE, 
         cluster_cols = TRUE, 
         annotation_col = annotation_col,
         annotation_colors = annotation_colors,
         display_numbers = TRUE,
         legend = FALSE,
         fontsize = 15)  

plt

ggsave("./pictures/Heatmap of diff expressed genes_type16.tiff", plot = plt, width = 8, height = 6, dpi = 300, bg = "white")

Plot of the distance between samples heatmap Расчет расстояний между образцами • Обычно используется евклидово расстояние (по умолчанию в DESeq2). • Оно вычисляется по нормализованным данным экспрессии (rlog() или vst()). • Чем меньше расстояние — тем более похожи образцы.

sampleDists_16 <- dist(t(assay(rlt_16)))
sampleDistMatrix_16 <- as.matrix(sampleDists_16)
rownames(sampleDistMatrix_16) <- paste(rlt_16$condition, rlt_16$patient, sep="_patient")
colnames(sampleDistMatrix_16) <- paste(rlt_16$condition, rlt_16$patient, sep="_patient")

plt <- pheatmap(sampleDistMatrix_16,
         clustering_distance_rows = "euclidean",
         clustering_distance_cols = "euclidean",
         fontsize = 12,
         legend = FALSE,
         display_numbers = TRUE,
         color = colors)

plt

ggsave("./pictures/Plot of the distance between samples_type16.tiff", plot = plt, width = 8, height = 6, dpi = 300, bg = "white")

Анализ обогащения для везикул типа 16

up_16 <- res_sign_16 %>% 
  as.data.frame() %>% 
  filter(log2FoldChange > 0)
down_16 <- res_sign_16 %>% 
  as.data.frame() %>% 
  filter(log2FoldChange < 0)
rownames(up_16)
[1] "Hsa-Mir-185_5p"     "Hsa-Mir-197_3p"     "Hsa-Mir-10-P3a_5p"  "Hsa-Mir-148-P3_5p*" "Hsa-Mir-30-P1a_3p*" "Hsa-Mir-150_3p*"    "Hsa-Mir-361_3p*"   
[8] "Hsa-Mir-10-P2b_5p"  "Hsa-Mir-126_3p*"   
rownames(down_16)
[1] "Hsa-Mir-340_5p"     "Hsa-Mir-181-P2c_5p" "Hsa-Mir-223_5p*"    "Hsa-Mir-30-P1c_3p*"

Переводим в miRBase • miRBase: https://www.mirbase.org/ • MirGeneDB: https://mirgenedb.org/

url <- "https://mirgenedb.org/browse/hsa"
page <- read_html(url)

Парсим таблицу

mir_table <- page %>%
  html_element("table") %>%
  html_table(fill = TRUE) 

mir_table <- mir_table[-c(1:3), c(1,2) ] 
colnames(mir_table) <- c("MirGeneDB_ID", "MiRBase_ID")
mir_table$MirGeneDB_ID <- sub(" V", "", mir_table$MirGeneDB_ID)

head(mir_table)
up_16_clean <- sub("_.*", "", row.names(up_16))
up_16_converted <- mir_table$MiRBase_ID[match(up_16_clean, mir_table$MirGeneDB_ID)]

down_16_clean <- sub("_.*", "", row.names(down_16))
down_16_converted <- mir_table$MiRBase_ID[match(down_16_clean, mir_table$MirGeneDB_ID)]
up_16_converted
[1] "hsa-mir-185" "hsa-mir-197" NA            "hsa-mir-152" "hsa-mir-30d" "hsa-mir-150" "hsa-mir-361" "hsa-mir-99b" NA           
down_16_converted
[1] "hsa-mir-340"  "hsa-mir-181d" "hsa-mir-223"  NA            

Конвертация в MIMATID в итоге заменила NA вручную на самые близкие, но это такая себе практика

NA Hsa-Mir-10-P3a_5p есть два соответствия: Hsa-Mir-10-P1c = hsa-mir-10a Hsa-Mir-10-P3b = hsa-mir-125a

NA Hsa-Mir-126_3p* есть одно соответствие: Hsa-Mir-126-P2 = hsa-mir-126

NA Hsa-Mir-30-P1c_3p* есть три соответствия: Hsa-Mir-30-P1a = hsa-mir-30d Hsa-Mir-30-P1b = hsa-mir-30a Hsa-Mir-30-P1d = hsa-mir-30e

[1] “Hsa-Mir-185_5p” “Hsa-Mir-197_3p” “Hsa-Mir-10-P3a_5p” “Hsa-Mir-148-P3_5p” ”Hsa-Mir-30-P1a_3p” “Hsa-Mir-150_3p
[7] ”Hsa-Mir-361_3p
” “Hsa-Mir-10-P2b_5p” “Hsa-Mir-126_3p
[1] ”Hsa-Mir-340_5p” ”Hsa-Mir-181-P2c_5p” ”Hsa-Mir-223_5p
” “Hsa-Mir-30-P1c_3p*”

MI (MicroRNA Gene ID) — это идентификатор предшественника (precursor) miRNA MIMAT (Mature miRNA ID) — это идентификатор зрелой (mature) miRNA, которая функционирует в клетке

up_16_converted <-  c("hsa-miR-185-5p", "hsa-miR-197-3p", "hsa-miR-152-5p", "hsa-miR-30d-3p", "hsa-miR-150-3p", "hsa-miR-361-3p", "hsa-miR-99b-5p", "hsa-miR-126-3p")
down_16_converted <- c("hsa-miR-340-5p", "hsa-miR-181d-5p", "hsa-miR-223-5p")


converted_mirna_up16 <- miRNAVersionConvert(up_16_converted)
converted_mirna_down16 <- miRNAVersionConvert(down_16_converted)
converted_mirna_up16
converted_mirna_down16

Запрос таргетов из базы multiMiR

targets16_up <- unique(get_multimir(org = "hsa", mirna = converted_mirna_up16$Accession, table = "validated")@data$target_symbol)
Searching mirecords ...
Searching mirtarbase ...
Searching tarbase ...
targets16_down <- unique(get_multimir(org = "hsa", mirna = converted_mirna_down16$Accession, table = "validated")@data$target_symbol)
Searching mirecords ...
Searching mirtarbase ...
Searching tarbase ...

Анализ обогащения, связанный со Biological Process

GO_enrich_up16_bp <- enrichGO(
  gene          = targets16_up,  
  OrgDb         = org.Hs.eg.db,
  keyType       = "SYMBOL",
  ont           = "BP", 
  pAdjustMethod = "BH",
  qvalueCutoff  = 0.05
)

GO_enrich_down16_bp <- enrichGO(
  gene          = targets16_down,  
  OrgDb         = org.Hs.eg.db,
  keyType       = "SYMBOL",
  ont           = "BP", 
  pAdjustMethod = "BH",
  qvalueCutoff  = 0.05
)
p1 <- dotplot(GO_enrich_up16_bp, showCategory = 20) + 
  ggtitle("BP for Upregulated Targets in Vesicles 16") + 
  theme(
    plot.title = element_text(size = 12, face = "bold"),
    axis.text.y = element_text(size = 12)
  )

p2 <- dotplot(GO_enrich_down16_bp, showCategory = 20) + 
  ggtitle("BP for Downregulated Targets in Vesicles 16") + 
  theme(
    plot.title = element_text(size = 12, face = "bold"),
    axis.text.y = element_text(size = 12)
  )
combined_plot <- p1 + p2
combined_plot
ggsave("./pictures/GO_enrichment_dotplot_BP_type16.tiff", plot = combined_plot, width = 16, height = 10, dpi = 300)

GO_enrich_UP16_BP <- enrichplot::pairwise_termsim(GO_enrich_up16_bp, method = "JC")

plt <- emapplot(GO_enrich_UP16_BP, 
         repel = TRUE,
         showCategory = 20) +
  ggtitle("BP for UPregulated targets for vesicles 16") +
  theme(
    plot.title = element_text(size = 12, face = "bold"),
    axis.text = element_text(size = 3)
    )   

plt

ggsave("./pictures/GO_enrichment_emapplot_BP_up_type16.tiff", plot = plt, width = 16, height = 10, dpi = 300)

GO_enrich_DOWN16_all <- enrichplot::pairwise_termsim(GO_enrich_down16_all, method = "JC")

plt <- emapplot(GO_enrich_DOWN16_all, 
         repel = TRUE,
         showCategory = 20) +
  ggtitle("BP for DOWNregulated targets for vesicles 16") +
  theme(
    plot.title = element_text(size = 12, face = "bold"),
    axis.text = element_text(size = 3)
    )    

plt

ggsave("./pictures/GO_enrichment_emapplot_BP_down_type16.tiff", plot = plt, width = 16, height = 10, dpi = 300)

GO Enrichment of Cellular Component

GO_enrich_down16_CC <- enrichGO(
  gene          = targets16_down,  
  OrgDb         = org.Hs.eg.db,
  keyType       = "SYMBOL",
  ont           = "CC", 
  pAdjustMethod = "BH",
  qvalueCutoff  = 0.05
)

GO_enrich_up16_CC <- enrichGO(
  gene          = targets16_up,  
  OrgDb         = org.Hs.eg.db,
  keyType       = "SYMBOL",
  ont           = "CC", 
  pAdjustMethod = "BH",
  qvalueCutoff  = 0.05
)
p1 <- dotplot(GO_enrich_up16_CC, showCategory = 20) + 
  ggtitle("6Cellular Component for Upregulated Targets in Vesicles 16") + 
  theme(
    plot.title = element_text(size = 12, face = "bold"),
    axis.text.y = element_text(size = 12)
  )

p2 <- dotplot(GO_enrich_down16_CC, showCategory = 20) + 
  ggtitle("Cellular Component for Downregulated Targets in Vesicles 16") + 
  theme(
    plot.title = element_text(size = 12, face = "bold"),
    axis.text.y = element_text(size = 12)
  )

p1 + p2

combined_plot <- p1 + p2
ggsave("./pictures/GO_enrichment_dotplot_CC_type16.tiff", plot = combined_plot, width = 16, height = 10, dpi = 300)

GO_enrich_UP16_CC <- enrichplot::pairwise_termsim(GO_enrich_up16_CC, method = "JC")

plt <- emapplot(GO_enrich_UP16_CC, 
         repel = TRUE,
         showCategory = 20) +
  ggtitle("Cellular processes for UPregulated targets for vesicles 16") +
  theme(
    plot.title = element_text(size = 12, face = "bold"),
    axis.text = element_text(size = 3)
    )   

plt

ggsave("./pictures/GO_enrichment_emapplot_CC_up_type16.tiff", plot = plt, width = 16, height = 10, dpi = 300)

GO_enrich_DOWN16_CC <- enrichplot::pairwise_termsim(GO_enrich_down16_CC, method = "JC")

plt <- emapplot(GO_enrich_DOWN16_CC, 
         repel = TRUE,
         showCategory = 25) +
  ggtitle("Cellular processes for DOWNregulated targets for vesicles 16") +
  theme(
    plot.title = element_text(size = 12, face = "bold"),
    axis.text = element_text(size = 3)
    )    

plt

ggsave("./pictures/GO_enrichment_emapplot_CC_down_type16.tiff", plot = plt, width = 16, height = 10, dpi = 300)

GO Enrichment of Molecular Function

GO_enrich_down16_MF <- enrichGO(
  gene          = targets16_down,  
  OrgDb         = org.Hs.eg.db,
  keyType       = "SYMBOL",
  ont           = "MF", 
  pAdjustMethod = "BH",
  qvalueCutoff  = 0.05
)

GO_enrich_up16_MF <- enrichGO(
  gene          = targets16_up,  
  OrgDb         = org.Hs.eg.db,
  keyType       = "SYMBOL",
  ont           = "MF", 
  pAdjustMethod = "BH",
  qvalueCutoff  = 0.05
)

p1 <- dotplot(GO_enrich_up16_MF, showCategory = 20) + 
  ggtitle("Molecular Function for Upregulated Targets in Vesicles 16") + 
  theme(
    plot.title = element_text(size = 12, face = "bold"),
    axis.text.y = element_text(size = 12)
  )

p2 <- dotplot(GO_enrich_down16_MF, showCategory = 20) + 
  ggtitle("Molecular Functiont for Downregulated Targets in Vesicles 16") + 
  theme(
    plot.title = element_text(size = 12, face = "bold"),
    axis.text.y = element_text(size = 12)
  )

combined_plot <- p1 + p2
combined_plot
ggsave("./pictures/GO_enrichment_dotplot_MF_type16.tiff", plot = combined_plot, width = 16, height = 10, dpi = 300)

GO_enrich_UP16_MF <- enrichplot::pairwise_termsim(GO_enrich_up16_MF, method = "JC")

plt <- emapplot(GO_enrich_UP16_MF, 
         repel = TRUE,
         showCategory = 25) +
  ggtitle("Molecular Function processes for UPregulated targets for vesicles 16") +
  theme(
    plot.title = element_text(size = 12, face = "bold"),
    axis.text = element_text(size = 3)
    )   

plt

ggsave("./pictures/GO_enrichment_emapplot_MF_up_type16.tiff", plot = plt, width = 16, height = 10, dpi = 300)

GO_enrich_DOWN16_MF <- enrichplot::pairwise_termsim(GO_enrich_down16_MF, method = "JC")

plt <- emapplot(GO_enrich_DOWN16_MF, 
         repel = TRUE,
         showCategory = 25) +
  ggtitle("Molecular Function processes for DOWNregulated targets for vesicles 16") +
  theme(
    plot.title = element_text(size = 12, face = "bold"),
    axis.text = element_text(size = 3)
    )   

plt

ggsave("./pictures/GO_enrichment_emapplot_MF_down_type16.tiff", plot = plt, width = 16, height = 10, dpi = 300)

LS0tCnRpdGxlOiAibWljcm8tUk5BIFZlc2ljbGVzIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdAotLS0KKirQo9GB0YLQsNC90LDQstC70LjQstCw0LXQvCDQvdC10L7QsdGF0L7QtNC40LzRi9C1INCx0LjQsdC70LjQvtGC0LrQuCoqCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShERVNlcTIpCmxpYnJhcnkocGhlYXRtYXApCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KGNsdXN0ZXJQcm9maWxlcikKbGlicmFyeShiaW9tYVJ0KQpsaWJyYXJ5KG9yZy5Icy5lZy5kYikKbGlicmFyeShFbmhhbmNlZFZvbGNhbm8pCmxpYnJhcnkoR2Vub21pY1JhbmdlcykKbGlicmFyeShtc2lnZGJyKQpsaWJyYXJ5KG11bHRpTWlSKQpsaWJyYXJ5KG1pUkJhc2VDb252ZXJ0ZXIpCmxpYnJhcnkoZW5yaWNocGxvdCkKbGlicmFyeSh2c24pCmxpYnJhcnkocnZlc3QpCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KGRicGx5cikKYGBgCiMjINCY0LzQv9C+0YDRgtC40YDRg9C10Lwg0LTQsNC90L3Ri9C1CmBgYHtyfQpzZXR3ZCgiL1VzZXJzL2Rhcmlha2lsaW5hL0dpdEh1Yi9NaWNyby1STkFfY2FyZGlvbG9neSIpCmNvbGRhdGEgPC0gcmVhZF90c3YoImRhdGEvcGhlbm90YWJsZVYudHN2Iiwgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkKY29sZGF0YSR0eXBlIDwtIGFzLmZhY3Rvcihjb2xkYXRhJHR5cGUpCmNvbGRhdGEkcGF0aWVudCA8LSBhcy5mYWN0b3IoY29sZGF0YSRwYXRpZW50KQpjb2xkYXRhJGNvbmRpdGlvbiA8LSBhcy5mYWN0b3IoY29sZGF0YSRjb25kaXRpb24pCmNvbGRhdGEgPC0gYXMuZGF0YS5mcmFtZShjb2xkYXRhKQpyb3duYW1lcyhjb2xkYXRhKSA8LSBjb2xkYXRhJHNhbXBsZQpjb2xkYXRhCmBgYAoKYGBge3J9CmNvdW50cyA8LSByZWFkLmNzdigiZGF0YS9taVIuQ291bnRzLmNzdiIsIGhlYWRlciA9IFRSVUUsIHNlcCA9ICIsIikKY291bnRzIDwtIGNvbHVtbl90b19yb3duYW1lcyhjb3VudHMsIHZhciA9ICJtaVJOQSIpCiNjb3VudHMgPC0gcm91bmQoY291bnRzKSAjINC10YHQu9C4INC40YHQv9C+0LvRjNC30YPQtdC8INC90L7RgNC80LDQu9C40LfQvtCy0LDQvdC90YvQtSDQtNCw0L3QvdGL0LUKaGVhZChjb3VudHMpCmBgYApgYGB7cn0KY29sbmFtZXMoY291bnRzKSA8LSBnc3ViKCJeWCIsICIiLCBjb2xuYW1lcyhjb3VudHMpKQpjb21tb25fc2FtcGxlcyA8LSBpbnRlcnNlY3QoY29sbmFtZXMoY291bnRzKSwgY29sZGF0YSRzYW1wbGUpCgpjb3VudHMgPC0gY291bnRzWywgYyhjb3VudHMkbWlSTkEsIGNvbW1vbl9zYW1wbGVzKV0gIApjb3VudHMgPC0gY291bnRzWywgcm93bmFtZXMoY29sZGF0YSldICPRgNCw0L3QttC40YDRg9GOINC/0L4g0LrQvtC70L7QvdC60Lgg0LIgY291bnRzINGC0LDQuiDQttC1INC60LDQuiDQuCDQvdCw0LfQstCw0L3QuNGPINGB0YLRgNC+0Log0LIgY29sZGF0YQpoZWFkKGNvdW50cykKYGBgCmBgYHtyfQphbm5vIDwtIHJlYWQuY3N2KCJkYXRhL2Fubm90YXRpb24ucmVwb3J0LmNzdiIsIGhlYWRlciA9IFRSVUUsIHNlcCA9ICIsIikKYW5ubyRTYW1wbGUubmFtZS5zLiA8LSBnc3ViKCItIiwgIi4iLCBhbm5vJFNhbXBsZS5uYW1lLnMuKQphbm5vIDwtIGFubm9bLCAtYygyOjUsIDcsIDE1KV0KCgpjb21tb25fc2FtcGxlcyA8LSBpbnRlcnNlY3QoYW5ubyRTYW1wbGUubmFtZS5zLiwgY29sZGF0YSRzYW1wbGUpCgphbm5vIDwtIGFubm9bYW5ubyRTYW1wbGUubmFtZS5zLiAlaW4lIGNvbW1vbl9zYW1wbGVzLCBdCmFubm8gPC0gYW5ub1ttYXRjaChyb3duYW1lcyhjb2xkYXRhKSwgYW5ubyRTYW1wbGUubmFtZS5zLiksIF0gI9GA0LDQvdC20LjRgNGD0Y4g0L/QviDQutC+0LvQvtC90LrQuCDQsiBjb3VudHMg0YLQsNC6INC20LUg0LrQsNC6INC4INC90LDQt9Cy0LDQvdC40Y8g0YHRgtGA0L7QuiDQsiBjb2xkYXRhCmFubm8KYGBgCiMjINCS0LXRgdGMINC00LDRgtCw0YHQtdGCCmBgYHtyfQphbm5vX2xvbmcgPC0gYW5ubyAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IC1TYW1wbGUubmFtZS5zLiwgbmFtZXNfdG8gPSAiUk5BX1R5cGUiLCB2YWx1ZXNfdG8gPSAiQ291bnQiKQoKcGx0IDwtIGdncGxvdChhbm5vX2xvbmcsIGFlcyh4ID0gU2FtcGxlLm5hbWUucy4sIHkgPSBDb3VudCwgZmlsbCA9IFJOQV9UeXBlKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHggPSAiU2FtcGxlIiwgeSA9ICJSZWFkIENvdW50IikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDMiKSAgIyDQmtGA0LDRgdC40LLRi9C1INGG0LLQtdGC0LAKCnByaW50KHBsdCkKZ2dzYXZlKCIuL3BpY3R1cmVzL2JhcnBsb3RfYWxsZGF0YXNldF9ub19ub3JtYWxpc2VkLnRpZmYiLCBwbG90ID0gcGx0LCB3aWR0aCA9IDgsIGhlaWdodCA9IDYsIGRwaSA9IDMwMCwgIGJnID0gIndoaXRlIikKYGBgCgpgYGB7cn0KYW5ub19sb25nIDwtIGFubm8gJT4lCiAgcm93d2lzZSgpICU+JQogIG11dGF0ZShhY3Jvc3MoLVNhbXBsZS5uYW1lLnMuLCB+IC4gLyBzdW0oY19hY3Jvc3MoLVNhbXBsZS5uYW1lLnMuKSkpKSAlPiUgCiAgdW5ncm91cCgpICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gLVNhbXBsZS5uYW1lLnMuLCBuYW1lc190byA9ICJSTkFfVHlwZSIsIHZhbHVlc190byA9ICJQcm9wb3J0aW9uIikKCnBsdCA8LSBnZ3Bsb3QoYW5ub19sb25nLCBhZXMoeCA9IFNhbXBsZS5uYW1lLnMuLCB5ID0gUHJvcG9ydGlvbiwgZmlsbCA9IFJOQV9UeXBlKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHggPSAiU2FtcGxlIiwgeSA9ICJQcm9wb3J0aW9uIikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDMiKQoKcGx0Cmdnc2F2ZSgiLi9waWN0dXJlcy9iYXJwbG90X2FsbGRhdGFzZXRfbm9ybWFsaXNlZC50aWZmIiwgcGxvdCA9IHBsdCwgd2lkdGggPSA4LCBoZWlnaHQgPSA2LCBkcGkgPSAzMDAsIGJnID0gIndoaXRlIikKYGBgCmBgYHtyfQpjb2xkYXRhJGNvbmRpdGlvbiA8LSByZWxldmVsKGNvbGRhdGEkY29uZGl0aW9uLCByZWYgPSAiYmVmb3JlIikKbW9kZWxNYXRyaXggPC0gbW9kZWwubWF0cml4KH50eXBlKmNvbmRpdGlvbiArIHBhdGllbnQsIGRhdGEgPSBjb2xkYXRhKQptb2RlbE1hdHJpeApgYGAKCgpgYGB7cn0KZGRzIDwtIERFU2VxRGF0YVNldEZyb21NYXRyaXgoY291bnREYXRhID0gY291bnRzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sRGF0YSA9IGNvbGRhdGEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXNpZ24gPSB+dHlwZSpjb25kaXRpb24gKyBwYXRpZW50KQpkZHMkY29uZGl0aW9uIDwtIHJlbGV2ZWwoZGRzJGNvbmRpdGlvbiwgcmVmID0gImJlZm9yZSIpCmRkcwpgYGAKYGBge3J9CmRpbShkZHMpCnNtYWxsZXN0R3JvdXBTaXplIDwtIDMKa2VlcCA8LSByb3dTdW1zKGNvdW50cyhkZHMpID49IDEwKSA+PSBzbWFsbGVzdEdyb3VwU2l6ZQpkZHMgPC0gZGRzW2tlZXAsXQpkaW0oZGRzKQpgYGAKKipSdW4gRGlmZmVyZW50aWFsIEV4cHJlc3Npb24gQW5hbHlzaXMgZm9yIGFsbCBkYXRhc2V0KioKYGBge3J9CmRkcyA8LSBERVNlcShkZHMsIGZpdFR5cGUgPSAicGFyYW1ldHJpYyIpCmRkcwpgYGAKCmBgYHtyfQpwbG90RGlzcEVzdHMoZGRzKQpgYGAKYGBge3J9CnJhd19jb3VudHMgPC0gY291bnRzKGRkcywgbm9ybWFsaXplZCA9IEZBTFNFKQpub3JtYWxpemVkX2NvdW50cyA8LSBjb3VudHMoZGRzLCBub3JtYWxpemVkID0gVFJVRSkKCmRmIDwtIGRhdGEuZnJhbWUoCiAgU2FtcGxlID0gcmVwKGNvbG5hbWVzKGRkcyksIDIpLAogIENvdW50cyA9IGMoY29sU3VtcyhyYXdfY291bnRzKSwgY29sU3Vtcyhub3JtYWxpemVkX2NvdW50cykpLAogIFR5cGUgPSByZXAoYygiUmF3IiwgIk5vcm1hbGl6ZWQiKSwgZWFjaCA9IG5jb2woZGRzKSkKKQoKcGx0IDwtIGdncGxvdChkZiwgYWVzKHggPSBTYW1wbGUsIHkgPSBDb3VudHMsIGZpbGwgPSBUeXBlKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnModGl0bGUgPSAiQ291bnRzIGJlZm9yZSBhbmQgYWZ0ZXIgbm9ybWFsaXphdGlvbiIsIHggPSAiU2FtcGxlIiwgeSA9ICJUb3RhbCBDb3VudHMiKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkKCnBsdApnZ3NhdmUoIi4vcGljdHVyZXMvQ291bnRzIGJlZm9yZSBhbmQgYWZ0ZXIgbm9ybWFsaXphdGlvbi50aWZmIiwgcGxvdCA9IHBsdCwgd2lkdGggPSA4LCBoZWlnaHQgPSA2LCBkcGkgPSAzMDAsIGJnID0gIndoaXRlIikKYGBgCioqcmxvZyDRgtGA0LDQvdGB0YTQvtGA0LzQsNGG0LjRjyoqCmBgYHtyfQpybHQgPC0gcmxvZyhkZHMpICAjcmxvZyBUcmFuc2Zvcm1hdGlvbgptZWFuU2RQbG90KGFzc2F5KHJsdCkpIAoKYGBgCmBgYHtyfQp2c2QgPC0gdmFyaWFuY2VTdGFiaWxpemluZ1RyYW5zZm9ybWF0aW9uKGRkcywgYmxpbmQ9RkFMU0UpIAptZWFuU2RQbG90KGFzc2F5KHZzZCkpICPQv9C+0LrQsNC30YvQstCw0LXRgiwg0LrQsNC6INC40LfQvNC10L3Rj9C10YLRgdGPINGB0YLQsNC90LTQsNGA0YLQvdC+0LUg0L7RgtC60LvQvtC90LXQvdC40LUg0LIg0LfQsNCy0LjRgdC40LzQvtGB0YLQuCDQvtGCINGB0YDQtdC00L3QtdCz0L4g0LfQvdCw0YfQtdC90LjRjyDRjdC60YHQv9GA0LXRgdGB0LjQuApgYGAKCioqUENBIHBsb3QqKgpgYGB7cn0KcGNhRGF0YSA8LSBwbG90UENBKHJsdCwgaW50Z3JvdXA9YygiY29uZGl0aW9uIiwgInR5cGUiLCAicGF0aWVudCIpLCByZXR1cm5EYXRhID0gVFJVRSkKcGVyY2VudFZhciA8LSByb3VuZCgxMDAgKiBhdHRyKHBjYURhdGEsICJwZXJjZW50VmFyIikpCgpwY2FEYXRhJGNvbmRpdGlvbl90eXBlIDwtIHBhc3RlKHBjYURhdGEkY29uZGl0aW9uLCBwY2FEYXRhJHR5cGUsIHNlcCA9ICJfIikKCmdncGxvdChwY2FEYXRhLCBhZXMoUEMxLCBQQzIsIHNoYXBlID0gcGF0aWVudCwgY29sb3IgPSBjb25kaXRpb25fdHlwZSkpICsKICBnZW9tX3BvaW50KHNpemUgPSAzKSArCiAgeGxhYihwYXN0ZTAoIlBDMTogIiwgcGVyY2VudFZhclsxXSwgIiUiKSkgKwogIHlsYWIocGFzdGUwKCJQQzI6ICIsIHBlcmNlbnRWYXJbMl0sICIlIikpICsgCiAgY29vcmRfZml4ZWQoKSArCiAgdGhlbWVfYncoKSArCiAgZ2d0aXRsZSgiUENBIHBsb3QgZm9yIGFsbCBkYXRhc2V0IGJlZm9yZSByZW1vdmluZyBkb25vciBlZmZlY3QiKSsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQyIikKYGBgCmBgYHtyfQphc3NheShybHQpIDwtIGxpbW1hOjpyZW1vdmVCYXRjaEVmZmVjdChhc3NheShybHQpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYXRjaCA9IGNvbERhdGEoZGRzKVssJ3BhdGllbnQnXSkKCnBjYURhdGEgPC0gcGxvdFBDQShybHQsIGludGdyb3VwPWMoImNvbmRpdGlvbiIsICJ0eXBlIiwgInBhdGllbnQiKSwgcmV0dXJuRGF0YSA9IFRSVUUpCnBlcmNlbnRWYXIgPC0gcm91bmQoMTAwICogYXR0cihwY2FEYXRhLCAicGVyY2VudFZhciIpKQoKcGNhRGF0YSRjb25kaXRpb25fdHlwZSA8LSBwYXN0ZShwY2FEYXRhJGNvbmRpdGlvbiwgcGNhRGF0YSR0eXBlLCBzZXAgPSAiXyIpCgpwbHQgPC0gZ2dwbG90KHBjYURhdGEsIGFlcyhQQzEsIFBDMiwgc2hhcGUgPSBwYXRpZW50LCBjb2xvciA9IGNvbmRpdGlvbl90eXBlKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDMpICsKICB4bGFiKHBhc3RlMCgiUEMxOiAiLCBwZXJjZW50VmFyWzFdLCAiJSIpKSArCiAgeWxhYihwYXN0ZTAoIlBDMjogIiwgcGVyY2VudFZhclsyXSwgIiUiKSkgKyAKICBjb29yZF9maXhlZCgpICsKICB0aGVtZV9idygpICsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQyIikKCnBsdApnZ3NhdmUoIi4vcGljdHVyZXMvUENBIHBsb3QgZm9yIGFsbCBkYXRhc2V0IGFmdGVyIHJlbW92aW5nIGRvbm9yIGVmZmVjdC50aWZmIiwgcGxvdCA9IHBsdCwgd2lkdGggPSA4LCBoZWlnaHQgPSA2LCBkcGkgPSAzMDAsIGJnID0gIndoaXRlIikKYGBgCioqUGxvdCBhIGhlYXRtYXAgb2YgNTAgbW9zdCBleHByZXNzZWQgZ2VuZXMqKgrQrdGC0L7RgiBoZWF0bWFwINC+0YLRgNCw0LbQsNC10YIg0YPRgNC+0LLQvdC4INGN0LrRgdC/0YDQtdGB0YHQuNC4INCz0LXQvdC+0LIsINCwINC90LUg0YDQsNC30L3QuNGG0YMg0LzQtdC20LTRgyDQs9GA0YPQv9C/0LDQvNC4LgrQptCy0LXRgtCwINC90LUg0L7Qt9C90LDRh9Cw0Y7RgiB1cC0g0LjQu9C4IGRvd24t0YDQtdCz0YPQu9GP0YbQuNGOINCyINGB0YDQsNCy0L3QtdC90LjQuCDRgSDQutC+0L3RgtGA0L7Qu9GM0L3QvtC5INCz0YDRg9C/0L/QvtC5LCDQv9C+0YLQvtC80YMg0YfRgtC+IGhlYXRtYXAg0L/QvtC60LDQt9GL0LLQsNC10YIg0LDQsdGB0L7Qu9GO0YLQvdGL0LUg0LfQvdCw0YfQtdC90LjRjyDRjdC60YHQv9GA0LXRgdGB0LjQuCwg0LAg0L3QtSBmb2xkIGNoYW5nZSEKYGBge3J9CnNlbGVjdCA8LSBvcmRlcihyb3dNZWFucyhjb3VudHMoZGRzLG5vcm1hbGl6ZWQ9VFJVRSkpLAogICAgICAgICAgICAgICAgZGVjcmVhc2luZz1UUlVFKVsxOjUwXQpkZiA8LSBhcy5kYXRhLmZyYW1lKGNvbERhdGEoZGRzKVssYygidHlwZSIsICJjb25kaXRpb24iKV0pCgpwbHQgPC0gcGhlYXRtYXAoYXNzYXkocmx0KVtzZWxlY3QsXSwgCiAgICAgICAgIGNsdXN0ZXJfcm93cyA9IFRSVUUsIAogICAgICAgICBzaG93X3Jvd25hbWVzID0gVFJVRSwgCiAgICAgICAgIGNsdXN0ZXJfY29scyA9IFRSVUUsIAogICAgICAgICBhbm5vdGF0aW9uX2NvbCA9IGRmLAogICAgICAgICBmb250c2l6ZV9yb3cgPSA2KSAKCnBsdApnZ3NhdmUoIi4vcGljdHVyZXMvUGxvdCBhIGhlYXRtYXAgb2YgNTAgbW9zdCBleHByZXNzZWQgZ2VuZXMudGlmZiIsIHBsb3QgPSBwbHQsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNiwgZHBpID0gMzAwLCBiZyA9ICJ3aGl0ZSIpCmBgYAoqKlBsb3Qgb2YgdGhlIGRpc3RhbmNlIGJldHdlZW4gc2FtcGxlcyBoZWF0bWFwKioK0KDQsNGB0YfQtdGCINGA0LDRgdGB0YLQvtGP0L3QuNC5INC80LXQttC00YMg0L7QsdGA0LDQt9GG0LDQvNC4CgnigKIJ0J7QsdGL0YfQvdC+INC40YHQv9C+0LvRjNC30YPQtdGC0YHRjyDQtdCy0LrQu9C40LTQvtCy0L4g0YDQsNGB0YHRgtC+0Y/QvdC40LUgKNC/0L4g0YPQvNC+0LvRh9Cw0L3QuNGOINCyIERFU2VxMikuCgnigKIJ0J7QvdC+INCy0YvRh9C40YHQu9GP0LXRgtGB0Y8g0L/QviDQvdC+0YDQvNCw0LvQuNC30L7QstCw0L3QvdGL0Lwg0LTQsNC90L3Ri9C8INGN0LrRgdC/0YDQtdGB0YHQuNC4IChybG9nKCkg0LjQu9C4IHZzdCgpKS4KCeKAognQp9C10Lwg0LzQtdC90YzRiNC1INGA0LDRgdGB0YLQvtGP0L3QuNC1IOKAlCDRgtC10Lwg0LHQvtC70LXQtSDQv9C+0YXQvtC20Lgg0L7QsdGA0LDQt9GG0YsuCmBgYHtyfQpzYW1wbGVEaXN0cyA8LSBkaXN0KHQoYXNzYXkocmx0KSkpCnNhbXBsZURpc3RNYXRyaXggPC0gYXMubWF0cml4KHNhbXBsZURpc3RzKQpyb3duYW1lcyhzYW1wbGVEaXN0TWF0cml4KSA8LSBwYXN0ZShybHQkY29uZGl0aW9uLCBybHQkdHlwZSwgc2VwPSJfdHlwZSIpCmNvbG5hbWVzKHNhbXBsZURpc3RNYXRyaXgpIDwtIHBhc3RlKHJsdCRjb25kaXRpb24sIHJsdCR0eXBlLCBzZXA9Il90eXBlIikKY29sb3JzIDwtIGNvbG9yUmFtcFBhbGV0dGUocmV2KGJyZXdlci5wYWwoOSwgIkJsdWVzIikpICkoMjU1KQoKcGx0IDwtIHBoZWF0bWFwKHNhbXBsZURpc3RNYXRyaXgsCiAgICAgICAgIGNsdXN0ZXJpbmdfZGlzdGFuY2Vfcm93cyA9ICJldWNsaWRlYW4iLAogICAgICAgICBjbHVzdGVyaW5nX2Rpc3RhbmNlX2NvbHMgPSAiZXVjbGlkZWFuIiwKICAgICAgICAgY29sb3IgPSBjb2xvcnMpCgpwbHQKZ2dzYXZlKCIuL3BpY3R1cmVzL1Bsb3Qgb2YgdGhlIGRpc3RhbmNlIGJldHdlZW4gc2FtcGxlcyBoZWF0bWFwLnRpZmYiLCBwbG90ID0gcGx0LCB3aWR0aCA9IDgsIGhlaWdodCA9IDYsIGRwaSA9IDMwMCwgYmcgPSAid2hpdGUiKQpgYGAKCiMjINCi0L7Qu9GM0LrQviDQstC10LfQuNC60YPQu9GLINGC0LjQv9CwIDE1MApgYGB7cn0KY29sZGF0YV8xNTAgPC0gY29sZGF0YVtjb2xkYXRhJHR5cGUgPT0gMTUwLCBdCnJvd25hbWVzKGNvbGRhdGFfMTUwKSA8LSBjb2xkYXRhXzE1MCRzYW1wbGUKY29sZGF0YV8xNTAKYGBgCmBgYHtyfQpjb21tb25fc2FtcGxlc18xNTAgPC0gaW50ZXJzZWN0KGNvbG5hbWVzKGNvdW50cyksIGNvbGRhdGFfMTUwJHNhbXBsZXMpCgpjb3VudHNfMTUwIDwtIGNvdW50c1ssIGMoY291bnRzJG1pUk5BLCBjb21tb25fc2FtcGxlcyldICAKY291bnRzXzE1MCA8LSBjb3VudHNfMTUwWywgcm93bmFtZXMoY29sZGF0YV8xNTApXSAj0YDQsNC90LbQuNGA0YPRjiDQv9C+INC60L7Qu9C+0L3QutC4INCyIGNvdW50cyDRgtCw0Log0LbQtSDQutCw0Log0Lgg0L3QsNC30LLQsNC90LjRjyDRgdGC0YDQvtC6INCyIGNvbGRhdGFfMTUwCmhlYWQoY291bnRzXzE1MCkKYGBgCmBgYHtyfQpjb2xkYXRhXzE1MCRjb25kaXRpb24gPC0gcmVsZXZlbChmYWN0b3IoY29sZGF0YV8xNTAkY29uZGl0aW9uKSwgcmVmID0gImJlZm9yZSIpCm1vZGVsTWF0cml4IDwtIG1vZGVsLm1hdHJpeCh+IDAgKyBwYXRpZW50ICsgY29uZGl0aW9uICwgY29sZGF0YSkKbW9kZWxNYXRyaXgKYGBgCioq0KHQvtC30LTQsNC10LwgREVTZXFEYXRhU2V0INC40Lcg0LzQsNGC0YDQuNGG0Ysg0LrQsNGD0L3RgtC+0LIqKgpgYGB7cn0KZGRzXzE1MCA8LSBERVNlcURhdGFTZXRGcm9tTWF0cml4KGNvdW50RGF0YSA9IGNvdW50c18xNTAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xEYXRhID0gY29sZGF0YV8xNTAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXNpZ24gPSB+IDAgKyBwYXRpZW50ICsgY29uZGl0aW9uKQpkZHNfMTUwJGNvbmRpdGlvbiA8LSByZWxldmVsKGRkc18xNTAkY29uZGl0aW9uLCByZWYgPSAiYmVmb3JlIikKZGRzXzE1MApgYGAKKirQpNC40LvRjNGC0YDQsNGG0LjRjyoqCmBgYHtyfQpkaW0oZGRzXzE1MCkKc21hbGxlc3RHcm91cFNpemUgPC0gMwprZWVwIDwtIHJvd1N1bXMoY291bnRzKGRkc18xNTApID49IDEwKSA+PSBzbWFsbGVzdEdyb3VwU2l6ZQpkZHNfMTUwIDwtIGRkc18xNTBba2VlcCxdCmRpbShkZHNfMTUwKQpgYGAKCioqUnVuIERpZmZlcmVudGlhbCBFeHByZXNzaW9uIEFuYWx5c2lzIGZvciAxNTAgdHlwZSoqCmBgYHtyfQpkZHNfMTUwIDwtIERFU2VxKGRkc18xNTAsIGZpdFR5cGUgPSAicGFyYW1ldHJpYyIpCmBgYAoKYGBge3J9CnBsb3REaXNwRXN0cyhkZHNfMTUwKQpgYGAKYGBge3J9CnJlc18xNTAgPC0gcmVzdWx0cyhkZHNfMTUwLCBjb250cmFzdD1jKCJjb25kaXRpb24iLCAiYmVmb3JlIiwgImFmdGVyIikpCnJlc18xNTAKYGBgCioqTUEgcGxvdCoqCgrQpNC40LvRjNGC0YDQsNGG0LjRjyDRgtC+0YfQtdC6INGBINC90LjQt9C60LjQvCDRgdGA0LXQtNC90LjQvCDRjdC60YHQv9GA0LXRgdGB0LjRgNC+0LLQsNC90LjQtdC8ICjQv9C+IGJhc2VNZWFuKS4KCeKAognQntCx0YvRh9C90L4g0L7RgtGB0LXQutCw0Y7RgtGB0Y8gYmFzZU1lYW4gPCAxLgoJMi4J0J7Qv9GA0LXQtNC10LvQtdC90LjQtSDQt9C90LDRh9C40LzRi9GFINCz0LXQvdC+0LIgKNGB0LjQvdC40LUg0YLQvtGH0LrQuCk6CgnigKIJ0JjRgdC/0L7Qu9GM0LfRg9C10YLRgdGPINC60YDQuNGC0LXRgNC40LkgcGFkaiA8IDAuMSDQv9C+INGD0LzQvtC70YfQsNC90LjRjiwg0LAg0L3QtSA8IDAuMDUhIApgYGB7cn0KdGlmZigiLi9waWN0dXJlcy9QbG90TUFfc3RhbmRhcnRfcGFkal8wLjA1X3R5cGUxNTAudGlmZiIsIAogICAgIHdpZHRoID0gOCwgaGVpZ2h0ID0gNiwgdW5pdHMgPSAiaW4iLCByZXMgPSAzMDAsIGJnID0gIndoaXRlIikKcGxvdE1BKHJlc18xNTAsIGFscGhhID0gMC4wNSwgeWxpbSA9IGMoLTgsIDgpKSAKZGV2Lm9mZigpCnBsb3RNQShyZXNfMTUwLCBhbHBoYSA9IDAuMDUsIHlsaW0gPSBjKC04LCA4KSkgCmBgYAoqKtCa0LDRgdGC0L7QvNC90YvQuSBNQSBwbG90INC/0L4gcC12YWx1ZSoqCmBgYHtyfQpyZXNfZGYgPC0gcmVzXzE1MCAlPiUKICBhcy5kYXRhLmZyYW1lKCkgJT4lCiAgbXV0YXRlKGNvbG9yID0gY2FzZV93aGVuKCAKICAgIHBhZGogPCAwLjA1ICB+ICJwYWRqIDwgMC4wNSIsICAgCiAgICBwdmFsdWUgPCAwLjA1ICB+ICJwdmFsdWUgPCAwLjA1IiwgCiAgICBUUlVFIH4gIkFsbCBtaWNyby1STkEiCiAgKSkKCnBsdCA8LSBnZ3Bsb3QocmVzX2RmLCBhZXMoeCA9IGJhc2VNZWFuLCB5ID0gbG9nMkZvbGRDaGFuZ2UsIGNvbG9yID0gY29sb3IpKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNywgc2l6ZSA9IDEpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJzb2xpZCIsIGNvbG9yID0gImdyYXk0MCIsIHNpemUgPSAxLjUpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiQWxsIG1pY3JvLVJOQSIgPSAiZ3JheTcwIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInB2YWx1ZSA8IDAuMDUiID0gImJsdWUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicGFkaiA8IDAuMDUiID0gInJlZCIpKSArCiAgc2NhbGVfeF9sb2cxMChsYWJlbHMgPSBzY2FsZXM6OnNjaWVudGlmaWMpICsgCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHggPSAibWVhbiBvZiBub3JtYWxpemVkIGNvdW50cyIsIAogICAgICAgeSA9ICJsb2cgZm9sZCBjaGFuZ2UiLCAKICAgICAgIGNvbG9yID0gTlVMTCkgICMg0J3QsNC30LLQsNC90LjQtSDQu9C10LPQtdC90LTRiwoKcGx0Cmdnc2F2ZSgiLi9waWN0dXJlcy/QoXVzdG9tIE1BcGxvdF90eXBlMTUwLnRpZmYiLCBwbG90ID0gcGx0LCB3aWR0aCA9IDgsIGhlaWdodCA9IDYsIGRwaSA9IDMwMCwgYmcgPSAid2hpdGUiKQpgYGAKKirQl9C90LDRh9C40LzRi9C1INGA0LXQt9GD0LvRjNGC0LDRgtGLKioKYGBge3J9CnNpZ25yZXNfMTUwIDwtIHJlc3VsdHMoZGRzXzE1MCwgY29udHJhc3Q9YygiY29uZGl0aW9uIiwgImJlZm9yZSIsICJhZnRlciIpLCBhbHBoYT0wLjA1KSAKc3VtbWFyeShzaWducmVzXzE1MCkKYGBgCkxldCdzIGFycmFuZ2VkIGl0IGJ5IGxvZzJGb2xkQ2hhbmdlOgpgYGB7cn0Kb3JkZXJfaW5kaWNlcyA8LSBvcmRlcigtcmVzXzE1MCRsb2cyRm9sZENoYW5nZSkKcmVzXzE1MFtvcmRlcl9pbmRpY2VzLCBdCmBgYApWaXN1YWxpc2F0aW9uIGZvciB0aGUgZmlyc3QgZ2VuZQpgYGB7cn0KI3Bsb3RDb3VudHMoZGRzXzE1MCwgZ2VuZT13aGljaC5tYXgocmVzXzE1MCRsb2cyRm9sZENoYW5nZSksIGludGdyb3VwPSJjb25kaXRpb24iKQpwbG90Q291bnRzKGRkc18xNTAsIGdlbmU9d2hpY2gubWluKHJlc18xNTAkcGFkaiksIGludGdyb3VwPSJjb25kaXRpb24iKQojcGxvdENvdW50cyhkZHMsIGdlbmU9cm93bmFtZXMocmVzKVt3aGljaC5taW4ocmVzJHBhZGpbd2hpY2gubWF4KHJlcyRsb2cyRm9sZENoYW5nZSldKV0sIGludGdyb3VwPSJjb25kaXRpb24iKQpgYGAKKipWb2xjYW5vIHBsb3QqKgpgYGB7cn0KcGx0IDwtIEVuaGFuY2VkVm9sY2FubyhyZXNfMTUwLAogICAgICAgICAgICAgICAgbGFiID0gcm93bmFtZXMocmVzXzE1MCksCiAgICAgICAgICAgICAgICB4ID0gImxvZzJGb2xkQ2hhbmdlIiwKICAgICAgICAgICAgICAgIHkgPSAicGFkaiIsCiAgICAgICAgICAgICAgICBwQ3V0b2ZmID0gMC4wNSwKICAgICAgICAgICAgICAgIEZDY3V0b2ZmID0gMSwKICAgICAgICAgICAgICAgIGxhYlNpemUgPSAzLjAsCiAgICAgICAgICAgICAgICBib3hlZExhYmVscyA9IEZBTFNFLAogICAgICAgICAgICAgICAgY29sID0gYygnYmxhY2snLCAnI0NCRDVFOCcsICcjQjNFMkNEJywgJyNGRENEQUMnKSwKICAgICAgICAgICAgICAgIGNvbEFscGhhID0gMSwKICAgICAgICAgICAgICAgIHRpdGxlID0gTlVMTCwgICAgICAgIAogICAgICAgICAgICAgICAgc3VidGl0bGUgPSBOVUxMKSAKCnBsdApnZ3NhdmUoIi4vcGljdHVyZXMvVm9sY2FubyBwbG90XzE1MHR5cGUudGlmZiIsIHBsb3QgPSBwbHQsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNiwgZHBpID0gMzAwLCBiZyA9ICJ3aGl0ZSIpCmBgYAoqKnJsb2cg0YLRgNCw0L3RgdGE0L7RgNC80LDRhtC40Y8qKgoJ4oCiCdCn0LXRgNC90YvQtSDRgtC+0YfQutC4IOKAkyDRgdGC0LDQvdC00LDRgNGC0L3QvtC1INC+0YLQutC70L7QvdC10L3QuNC1INC+0YLQtNC10LvRjNC90YvRhSDQs9C10L3QvtCyLgoJ4oCiCdCa0YDQsNGB0L3QsNGPINC70LjQvdC40Y8g4oCTINGB0LPQu9Cw0LbQtdC90L3Ri9C5INGC0YDQtdC90LQg0LfQsNCy0LjRgdC40LzQvtGB0YLQuCBTRCDQvtGCINGB0YDQtdC00L3QtdCz0L4g0LfQvdCw0YfQtdC90LjRjyDRjdC60YHQv9GA0LXRgdGB0LjQuC4KCeKAognQldGB0LvQuCDQutGA0LDRgdC90LDRjyDQu9C40L3QuNGPINC90LDQutC70L7QvdC10L3QsCDQstCy0LXRgNGFIOKGkiDRgdGC0LDQvdC00LDRgNGC0L3QvtC1INC+0YLQutC70L7QvdC10L3QuNC1INGA0LDRgdGC0ZHRgiDRgSDRg9Cy0LXQu9C40YfQtdC90LjQtdC8INGB0YDQtdC00L3QtdCz0L4gKNC/0LvQvtGF0LDRjyDQvdC+0YDQvNCw0LvQuNC30LDRhtC40Y8pLgoJ4oCiCdCV0YHQu9C4INC60YDQsNGB0L3QsNGPINC70LjQvdC40Y8g0L/RgNC40LzQtdGA0L3QviDQs9C+0YDQuNC30L7QvdGC0LDQu9GM0L3QsCDihpIg0L3QvtGA0LzQsNC70LjQt9Cw0YbQuNGPINGB0YDQsNCx0L7RgtCw0LvQsCDRhdC+0YDQvtGI0L4uCmBgYHtyfQpybHRfMTUwIDwtIHJsb2coZGRzXzE1MCkgCm1lYW5TZFBsb3QoYXNzYXkocmx0XzE1MCkpICAj0L/QvtC60LDQt9GL0LLQsNC10YIsINC60LDQuiDQuNC30LzQtdC90Y/QtdGC0YHRjyDRgdGC0LDQvdC00LDRgNGC0L3QvtC1INC+0YLQutC70L7QvdC10L3QuNC1INCyINC30LDQstC40YHQuNC80L7RgdGC0Lgg0L7RgiDRgdGA0LXQtNC90LXQs9C+INC30L3QsNGH0LXQvdC40Y8g0Y3QutGB0L/RgNC10YHRgdC40LguCmBgYAoqKlBDQSBwbG90KioKUENBIOKAkyDRjdGC0L4g0LzQtdGC0L7QtCDRgdC90LjQttC10L3QuNGPINGA0LDQt9C80LXRgNC90L7RgdGC0LgsINC60L7RgtC+0YDRi9C5INC/0L7QutCw0LfRi9Cy0LDQtdGCINGA0LDQt9C70LjRh9C40Y8g0LzQtdC20LTRgyDQvtCx0YDQsNC30YbQsNC80LguINCh0YLRgNC+0LjRgtGB0Y8g0L3QsCDQvtGB0L3QvtCy0LUg0YDQsNC30LvQuNGH0LjQuSDQsiDRjdC60YHQv9GA0LXRgdGB0LjQuCDQv9C+INCy0YHQtdC8INCz0LXQvdCw0LwsINC00LDQttC1INC10YHQu9C4INC+0L3QuCDQvdC1INGP0LLQu9GP0Y7RgtGB0Y8g0LfQvdCw0YfQuNC80L4g0LTQuNGE0YTQtdGA0LXQvdGG0LjQsNC70YzQvdC+INGN0LrRgdC/0YDQtdGB0YHQuNGA0L7QstCw0L3QvdGL0LzQuC4KCeKAognQntC90L4g0L3QtSDQvdCw0LrQu9Cw0LTRi9Cy0LDQtdGCINGB0YLQsNGC0LjRgdGC0LjRh9C10YHQutC40YUg0L/QvtGA0L7Qs9C+0LIg0LLRgNC+0LTQtSBwYWRqIDwgMC4wNSDQuNC70LggfGxvZzJGb2xkQ2hhbmdlfCA+IDEsINCwINC/0YDQvtGB0YLQviDQuNGJ0LXRgiDQvdCw0LjQsdC+0LvRjNGI0LjQtSDQuNGB0YLQvtGH0L3QuNC60Lgg0LLQsNGA0LjQsNCx0LXQu9GM0L3QvtGB0YLQuCDRgdGA0LXQtNC4INCy0YHQtdGFINC40LfQvNC10YDQtdC90LjQuS4KCeKAognQn9C+0Y3RgtC+0LzRgyDQtNCw0LbQtSDQvdC10LHQvtC70YzRiNC40LUg0LjQt9C80LXQvdC10L3QuNGPINGN0LrRgdC/0YDQtdGB0YHQuNC4INC80L7Qs9GD0YIg0YTQvtGA0LzQuNGA0L7QstCw0YLRjCDQutC70LDRgdGC0LXRgNGLINC4INGA0LDQt9C70LjRh9Cw0YLRjCDQs9GA0YPQv9C/0Ysg0LIgUENBLCDQtdGB0LvQuCDRjdGC0Lgg0LjQt9C80LXQvdC10L3QuNGPINGB0LjRgdGC0LXQvNCw0YLQuNGH0L3RiyDQvNC10LbQtNGDINC+0LHRgNCw0LfRhtCw0LzQuC4KYGBge3J9CnBjYURhdGEgPC0gcGxvdFBDQShybHRfMTUwLCBpbnRncm91cD1jKCJjb25kaXRpb24iLCAicGF0aWVudCIpLCByZXR1cm5EYXRhID0gVFJVRSkKcGVyY2VudFZhciA8LSByb3VuZCgxMDAgKiBhdHRyKHBjYURhdGEsICJwZXJjZW50VmFyIikpCgpnZ3Bsb3QocGNhRGF0YSwgYWVzKFBDMSwgUEMyLCBzaGFwZSA9IHBhdGllbnQsIGNvbG9yID0gY29uZGl0aW9uKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDMpICsKICB4bGFiKHBhc3RlMCgiUEMxOiAiLCBwZXJjZW50VmFyWzFdLCAiJSIpKSArCiAgeWxhYihwYXN0ZTAoIlBDMjogIiwgcGVyY2VudFZhclsyXSwgIiUiKSkgKyAKICBjb29yZF9maXhlZCgpICsKICB0aGVtZV9idygpICsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQyIikKYGBgCmBgYHtyfQphc3NheShybHRfMTUwKSA8LSBsaW1tYTo6cmVtb3ZlQmF0Y2hFZmZlY3QoYXNzYXkocmx0XzE1MCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhdGNoID0gY29sRGF0YShkZHNfMTUwKVssJ3BhdGllbnQnXSkKCnBjYURhdGEgPC0gcGxvdFBDQShybHRfMTUwLCBpbnRncm91cD1jKCJjb25kaXRpb24iLCAicGF0aWVudCIpLCByZXR1cm5EYXRhID0gVFJVRSkKcGVyY2VudFZhciA8LSByb3VuZCgxMDAgKiBhdHRyKHBjYURhdGEsICJwZXJjZW50VmFyIikpCgpwbHQgPC0gZ2dwbG90KHBjYURhdGEsIGFlcyhQQzEsIFBDMiwgc2hhcGUgPSBwYXRpZW50LCBjb2xvciA9IGNvbmRpdGlvbikpICsKICBnZW9tX3BvaW50KHNpemUgPSAzKSArCiAgeGxhYihwYXN0ZTAoIlBDMTogIiwgcGVyY2VudFZhclsxXSwgIiUiKSkgKwogIHlsYWIocGFzdGUwKCJQQzI6ICIsIHBlcmNlbnRWYXJbMl0sICIlIikpICsgCiAgY29vcmRfZml4ZWQoKSArCiAgdGhlbWVfYncoKSArCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiU2V0MiIpCnBsdApnZ3NhdmUoIi4vcGljdHVyZXMvUENBIHBsb3QgZm9yIHR5cGUgMTUwIGFmdGVyIHJlbW92aW5nIGRvbm9yIGVmZmVjdC50aWZmIiwgcGxvdCA9IHBsdCwgd2lkdGggPSA4LCBoZWlnaHQgPSA2LCBkcGkgPSAzMDAsIGJnID0gIndoaXRlIikKYGBgCioqUGxvdCBhIGhlYXRtYXAgb2YgZGlmZiBleHByZXNzZWQgZ2VuZXMqKgoKYGBge3J9CnJlc19zaWduXzE1MCA8LSBzdWJzZXQocmVzXzE1MCwgcGFkaiA8IDAuMDUgJiAhaXMubmEocGFkaikgJiBhYnMobG9nMkZvbGRDaGFuZ2UpID4gMS4wKQpyZXNfc2lnbl8xNTAgPC0gcmVzX3NpZ25fMTUwW29yZGVyKHJlc19zaWduXzE1MCRsb2cyRm9sZENoYW5nZSwgZGVjcmVhc2luZyA9IFRSVUUpLCBdCgpzaWdfZ2VuZXMgPC0gcm93bmFtZXMocmVzX3NpZ25fMTUwKSAgIyDQn9C+0LvRg9GH0LDQtdC8INC40LzQtdC90LAg0LPQtdC90L7Qsiwg0LrQvtGC0L7RgNGL0LUg0L/RgNC+0YjQu9C4INGE0LjQu9GM0YLRgNCw0YbQuNGOCgpkZV9tYXQgPC0gYXNzYXkocmx0XzE1MClbc2lnX2dlbmVzLCBdIApkYXRhbWF0cml4IDwtIGRlX21hdAoKYW5ub3RhdGlvbl9jb2wgPC0gZGF0YS5mcmFtZShjb25kaXRpb24gPSBjb2xkYXRhXzE1MCRjb25kaXRpb24pCnJvd25hbWVzKGFubm90YXRpb25fY29sKSA8LSBjb2xuYW1lcyhkYXRhbWF0cml4KQoKYW5ub3RhdGlvbl9jb2xvcnMgPC0gbGlzdCgKICBjb25kaXRpb24gPSBjKCJiZWZvcmUiID0gIiNGRkNDMDAiLCAiYWZ0ZXIiID0gIiMzMzk5RkYiKQopCgpwbHQgPC0gcGhlYXRtYXAoZGF0YW1hdHJpeCwgCiAgICAgICAgIGNsdXN0ZXJfcm93cyA9IFRSVUUsIAogICAgICAgICBzaG93X3Jvd25hbWVzID0gVFJVRSwgCiAgICAgICAgIGNsdXN0ZXJfY29scyA9IFRSVUUsIAogICAgICAgICBhbm5vdGF0aW9uX2NvbCA9IGFubm90YXRpb25fY29sLAogICAgICAgICBhbm5vdGF0aW9uX2NvbG9ycyA9IGFubm90YXRpb25fY29sb3JzLAogICAgICAgICBkaXNwbGF5X251bWJlcnMgPSBUUlVFLAogICAgICAgICBsZWdlbmQgPSBUUlVFLAogICAgICAgICBmb250c2l6ZSA9IDE1KSAgCnBsdApnZ3NhdmUoIi4vcGljdHVyZXMvSGVhdG1hcCBvZiBkaWZmIGV4cHJlc3NlZCBnZW5lc190eXBlMTUwLnRpZmYiLCBwbG90ID0gcGx0LCB3aWR0aCA9IDgsIGhlaWdodCA9IDYsIGRwaSA9IDMwMCwgYmcgPSAid2hpdGUiKQpgYGAKKipQbG90IG9mIHRoZSBkaXN0YW5jZSBiZXR3ZWVuIHNhbXBsZXMgaGVhdG1hcCoqCtCg0LDRgdGH0LXRgiDRgNCw0YHRgdGC0L7Rj9C90LjQuSDQvNC10LbQtNGDINC+0LHRgNCw0LfRhtCw0LzQuAoJ4oCiCdCe0LHRi9GH0L3QviDQuNGB0L/QvtC70YzQt9GD0LXRgtGB0Y8g0LXQstC60LvQuNC00L7QstC+INGA0LDRgdGB0YLQvtGP0L3QuNC1ICjQv9C+INGD0LzQvtC70YfQsNC90LjRjiDQsiBERVNlcTIpLgoJ4oCiCdCe0L3QviDQstGL0YfQuNGB0LvRj9C10YLRgdGPINC/0L4g0L3QvtGA0LzQsNC70LjQt9C+0LLQsNC90L3Ri9C8INC00LDQvdC90YvQvCDRjdC60YHQv9GA0LXRgdGB0LjQuCAocmxvZygpINC40LvQuCB2c3QoKSkuCgnigKIJ0KfQtdC8INC80LXQvdGM0YjQtSDRgNCw0YHRgdGC0L7Rj9C90LjQtSDigJQg0YLQtdC8INCx0L7Qu9C10LUg0L/QvtGF0L7QttC4INC+0LHRgNCw0LfRhtGLLgoKYGBge3J9CnNhbXBsZURpc3RzXzE1MCA8LSBkaXN0KHQoYXNzYXkocmx0XzE1MCkpKQpzYW1wbGVEaXN0TWF0cml4XzE1MCA8LSBhcy5tYXRyaXgoc2FtcGxlRGlzdHNfMTUwKQpyb3duYW1lcyhzYW1wbGVEaXN0TWF0cml4XzE1MCkgPC0gcGFzdGUocmx0XzE1MCRjb25kaXRpb24sIHJsdF8xNTAkcGF0aWVudCwgc2VwPSJfcGF0aWVudCIpCmNvbG5hbWVzKHNhbXBsZURpc3RNYXRyaXhfMTUwKSA8LSBwYXN0ZShybHRfMTUwJGNvbmRpdGlvbiwgcmx0XzE1MCRwYXRpZW50LCBzZXA9Il9wYXRpZW50IikKY29sb3JzIDwtIGNvbG9yUmFtcFBhbGV0dGUocmV2KGJyZXdlci5wYWwoOSwgIkJsdWVzIikpICkoMjU1KQoKcGx0IDwtIHBoZWF0bWFwKHNhbXBsZURpc3RNYXRyaXhfMTUwLAogICAgICAgICBjbHVzdGVyaW5nX2Rpc3RhbmNlX3Jvd3MgPSAiZXVjbGlkZWFuIiwKICAgICAgICAgY2x1c3RlcmluZ19kaXN0YW5jZV9jb2xzID0gImV1Y2xpZGVhbiIsCiAgICAgICAgIGZvbnRzaXplID0gMTIsCiAgICAgICAgIGxlZ2VuZCA9IEZBTFNFLAogICAgICAgICBkaXNwbGF5X251bWJlcnMgPSBUUlVFLAogICAgICAgICBjb2xvciA9IGNvbG9ycykKcGx0Cmdnc2F2ZSgiLi9waWN0dXJlcy9QbG90IG9mIHRoZSBkaXN0YW5jZSBiZXR3ZWVuIHNhbXBsZXNfdHlwZTE1MC50aWZmIiwgcGxvdCA9IHBsdCwgd2lkdGggPSA4LCBoZWlnaHQgPSA2LCBkcGkgPSAzMDAsIGJnID0gIndoaXRlIikKYGBgCgojIyMg0JDQvdCw0LvQuNC3INC+0LHQvtCz0LDRidC10L3QuNGPINC00LvRjyDQstC10LfQuNC60YPQuyDRgtC40L/QsCAxNTAgIyMjCmBgYHtyfQp1cF8xNTAgPC0gcmVzX3NpZ25fMTUwICU+JSAKICBhcy5kYXRhLmZyYW1lKCkgJT4lIAogIGZpbHRlcihsb2cyRm9sZENoYW5nZSA+IDApCmRvd25fMTUwIDwtIHJlc19zaWduXzE1MCAlPiUgCiAgYXMuZGF0YS5mcmFtZSgpICU+JSAKICBmaWx0ZXIobG9nMkZvbGRDaGFuZ2UgPCAwKQpyb3duYW1lcyh1cF8xNTApCnJvd25hbWVzKGRvd25fMTUwKQpgYGAK0L/QtdGA0LXQstC10LvQsCDQstGA0YPRh9C90YPRjjogaHR0cHM6Ly9taXJnZW5lZGIub3JnL2Jyb3dzZS9oc2EKSHNhLU1pci0zMjggPQloc2EtbWlyLTMyOCAJRXV0aGVyaWEgIOKAlCDQutC70LDQtNCwINC30LLQtdGA0LXQuSwg0LLQutC70Y7Rh9Cw0Y7RidCw0Y8g0L/Qu9Cw0YbQtdC90YLQsNGA0L3Ri9GFINC4INGA0LDQt9C70LjRh9C90YvQtSDQstGL0LzQtdGA0YjQuNC1INC40L3RhNGA0LDQutC70LDRgdGB0YsuIApIc2EtTWlyLTEzMy1QMSA9IGhzYS1taXItMTMzYS0xIEduYXRob3N0b21hdGEgCkhzYS1NaXItMTMzLVAyID0gaHNhLW1pci0xMzNiIEduYXRob3N0b21hdGEKSHNhLU1pci0xMzMtUDMgPSBoc2EtbWlyLTEzM2EtMiBHbmF0aG9zdG9tYXRhCtC10YHRgtGMINGC0L7Qu9GM0LrQviBoc2EtbWlSLTEzM2EtM3AKSHNhLU1pci00OTkJPSBoc2EtbWlyLTQ5OWEgVmVydGVicmF0YQpIc2EtTWlyLTIwOC1QMgloc2EtbWlyLTIwOGEgVmVydGVicmF0YQoJ4oCiCW1pUkJhc2U6IGh0dHBzOi8vd3d3Lm1pcmJhc2Uub3JnLwoJ4oCiCU1pckdlbmVEQjogaHR0cHM6Ly9taXJnZW5lZGIub3JnLwpgYGB7cn0KbWlybmFfbmFtZXNfdXAgPC0gYygiaHNhLW1pUi0zMjgtM3AiKQptaXJuYV9uYW1lc19kb3duIDwtIGMoImhzYS1taVItMTMzYS0zcCIsICJoc2EtbWlSLTEzM2EtM3AiLCAiaHNhLW1pUi0yMDhhLTNwIiwgImhzYS1taVItNDk5YS01cCIpCmBgYAoKKirQmtC+0L3QstC10YDRgtCw0YbQuNGPINCyIE1JTUFUSUQqKgpgYGB7cn0KY29udmVydGVkX21pcm5hX3VwIDwtIG1pUk5BVmVyc2lvbkNvbnZlcnQobWlybmFfbmFtZXNfdXApCmNvbnZlcnRlZF9taXJuYV9kb3duIDwtIG1pUk5BVmVyc2lvbkNvbnZlcnQobWlybmFfbmFtZXNfZG93bikKY29udmVydGVkX21pcm5hX3VwCmNvbnZlcnRlZF9taXJuYV9kb3duCmBgYAoKKirQl9Cw0L/RgNC+0YEg0YLQsNGA0LPQtdGC0L7QsiDQuNC3INCx0LDQt9GLIG11bHRpTWlSKiogCmBgYHtyfQp0YXJnZXRzMTUwX2Rvd24gPC0gdW5pcXVlKGdldF9tdWx0aW1pcihvcmcgPSAiaHNhIiwgbWlybmEgPSBjb252ZXJ0ZWRfbWlybmFfdXAkQWNjZXNzaW9uLCB0YWJsZSA9ICJ2YWxpZGF0ZWQiKUBkYXRhJHRhcmdldF9zeW1ib2wpCnRhcmdldHMxNTBfdXAgPC0gdW5pcXVlKGdldF9tdWx0aW1pcihvcmcgPSAiaHNhIiwgbWlybmEgPSBjb252ZXJ0ZWRfbWlybmFfZG93biRBY2Nlc3Npb24sIHRhYmxlID0gInZhbGlkYXRlZCIpQGRhdGEkdGFyZ2V0X3N5bWJvbCkKI3dyaXRlTGluZXModGFyZ2V0c19kb3duLCAidGFyZ2V0c19kb3duMTUwX2xpc3QudHh0IikKI3dyaXRlTGluZXModGFyZ2V0c191cCwgInRhcmdldHNfdXAxNTBfbGlzdC50eHQiKQpgYGAKCgoqKtCQ0L3QsNC70LjQtyDQvtCx0L7Qs9Cw0YnQtdC90LjRjywg0YHQstGP0LfQsNC90L3Ri9C5INGB0L4gQmlvbG9naWNhbCBQcm9jZXNzZXMqKgpgYGB7cn0KIyBtc2lnX2dvX2JwIDwtIG1zaWdkYnIoc3BlY2llcyA9ICJIb21vIHNhcGllbnMiLCBjYXRlZ29yeSA9ICJDNyIsIHN1YmNhdGVnb3J5ID0gIklNTVVORVNJR0RCIikKIyAKIyBHT19lbnJpY2hfdXAxNTBfaW1tdW0gPC0gZW5yaWNoZXIoZ2VuZSA9IHRhcmdldHMxNTBfdXAsIFRFUk0yR0VORSA9IG1zaWdfZ29fYnBbLCBjKCJnc19uYW1lIiwgImdlbmVfc3ltYm9sIildKQojIEdPX2VucmljaF9kb3duMTUwX2ltbXVuIDwtIGVucmljaGVyKGdlbmUgPSB0YXJnZXRzMTUwX2Rvd24sIFRFUk0yR0VORSA9IG1zaWdfZ29fYnBbLCBjKCJnc19uYW1lIiwgImdlbmVfc3ltYm9sIildKQoKR09fZW5yaWNoX2Rvd24xNTBfYnAgPC0gZW5yaWNoR08oCiAgZ2VuZSAgICAgICAgICA9IHRhcmdldHMxNTBfZG93biwgIAogIE9yZ0RiICAgICAgICAgPSBvcmcuSHMuZWcuZGIsCiAga2V5VHlwZSAgICAgICA9ICJTWU1CT0wiLAogIG9udCAgICAgICAgICAgPSAiQlAiLCAKICBwQWRqdXN0TWV0aG9kID0gIkJIIiwKICBxdmFsdWVDdXRvZmYgID0gMC4wNQopCgpHT19lbnJpY2hfdXAxNTBfYnAgPC0gZW5yaWNoR08oCiAgZ2VuZSAgICAgICAgICA9IHRhcmdldHMxNTBfdXAsICAKICBPcmdEYiAgICAgICAgID0gb3JnLkhzLmVnLmRiLAogIGtleVR5cGUgICAgICAgPSAiU1lNQk9MIiwKICBvbnQgICAgICAgICAgID0gIkJQIiwgCiAgcEFkanVzdE1ldGhvZCA9ICJCSCIsCiAgcXZhbHVlQ3V0b2ZmICA9IDAuMDUKKQpgYGAKCioq0JLQuNC30YPQsNC70LjQt9Cw0YbQuNGPIEJpb2xvZ2ljYWwgUHJvY2Vzc2VzKioKYGBge3J9CnAxIDwtIGRvdHBsb3QoR09fZW5yaWNoX3VwMTUwX2JwLCBzaG93Q2F0ZWdvcnkgPSAyMCkgKyAKICBnZ3RpdGxlKCJCUCBmb3IgVXByZWd1bGF0ZWQgVGFyZ2V0cyBpbiBWZXNpY2xlcyAxNTAiKSArIAogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpLAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpCiAgKQoKcDIgPC0gZG90cGxvdChHT19lbnJpY2hfZG93bjE1MF9icCwgc2hvd0NhdGVnb3J5ID0gMjApICsgCiAgZ2d0aXRsZSgiQlAgZm9yIERvd25yZWd1bGF0ZWQgVGFyZ2V0cyBpbiBWZXNpY2xlcyAxNTAiKSArIAogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpLAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpCiAgKQoKcDEgKyBwMgoKY29tYmluZWRfcGxvdCA8LSBwMSArIHAyCgpnZ3NhdmUoIi4vcGljdHVyZXMvR09fZW5yaWNobWVudF9kb3RwbG90X0JQX3R5cGUxNTAudGlmZiIsIHBsb3QgPSBjb21iaW5lZF9wbG90LCB3aWR0aCA9IDE2LCBoZWlnaHQgPSAxMCwgZHBpID0gMzAwKQpgYGAKYGBge3J9CkdPX2VucmljaF9VUDE1MF9CUCA8LSBlbnJpY2hwbG90OjpwYWlyd2lzZV90ZXJtc2ltKEdPX2VucmljaF91cDE1MF9icCwgbWV0aG9kID0gIkpDIikKCnBsdCA8LSBlbWFwcGxvdChHT19lbnJpY2hfVVAxNTBfQlAsIAogICAgICAgICByZXBlbCA9IFRSVUUsCiAgICAgICAgIHNob3dDYXRlZ29yeSA9IDIwKSArCiAgZ2d0aXRsZSgiQWxsIHByb2Nlc3NlcyBmb3IgVVByZWd1bGF0ZWQgdGFyZ2V0cyBmb3IgdmVzaWNsZXMgMTUwIikgKwogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpLAogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAzKQogICAgKSAgIAoKcGx0CgpnZ3NhdmUoIi4vcGljdHVyZXMvR09fZW5yaWNobWVudF9lbWFwcGxvdF9CUF91cF90eXBlMTUwLnRpZmYiLCBwbG90ID0gcGx0LCB3aWR0aCA9IDE2LCBoZWlnaHQgPSAxMCwgZHBpID0gMzAwKQpgYGAKCmBgYHtyfQpHT19lbnJpY2hfRE9XTjE1MF9CUCA8LSBlbnJpY2hwbG90OjpwYWlyd2lzZV90ZXJtc2ltKEdPX2VucmljaF9kb3duMTUwX2JwLCBtZXRob2QgPSAiSkMiKQoKcGx0IDwtIGVtYXBwbG90KEdPX2VucmljaF9ET1dOMTUwX0JQLCAKICAgICAgICAgcmVwZWwgPSBUUlVFLAogICAgICAgICBzaG93Q2F0ZWdvcnkgPSAyMCkgKwogIGdndGl0bGUoIkFsbCBwcm9jZXNzZXMgZm9yIERPV05yZWd1bGF0ZWQgdGFyZ2V0cyBmb3IgdmVzaWNsZXMgMTUwIikgKwogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpLAogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAzKQogICAgKSAgICAKCnBsdAoKZ2dzYXZlKCIuL3BpY3R1cmVzL0dPX2VucmljaG1lbnRfZW1hcHBsb3RfQlBfZG93bl90eXBlMTUwLnRpZmYiLCBwbG90ID0gcGx0LCB3aWR0aCA9IDE2LCBoZWlnaHQgPSAxMCwgZHBpID0gMzAwKQpgYGAKCioqR08gRW5yaWNobWVudCBvZiBDZWxsdWxhciBDb21wb25lbnQqKgpgYGB7cn0KIyBtc2lnX2dvX2JwIDwtIG1zaWdkYnIoc3BlY2llcyA9ICJIb21vIHNhcGllbnMiLCBjYXRlZ29yeSA9ICJDNyIsIHN1YmNhdGVnb3J5ID0gIklNTVVORVNJR0RCIikKIyAKIyBHT19lbnJpY2hfdXAxNTBfaW1tdW0gPC0gZW5yaWNoZXIoZ2VuZSA9IHRhcmdldHMxNTBfdXAsIFRFUk0yR0VORSA9IG1zaWdfZ29fYnBbLCBjKCJnc19uYW1lIiwgImdlbmVfc3ltYm9sIildKQojIEdPX2VucmljaF9kb3duMTUwX2ltbXVuIDwtIGVucmljaGVyKGdlbmUgPSB0YXJnZXRzMTUwX2Rvd24sIFRFUk0yR0VORSA9IG1zaWdfZ29fYnBbLCBjKCJnc19uYW1lIiwgImdlbmVfc3ltYm9sIildKQoKR09fZW5yaWNoX2Rvd24xNTBfQ0MgPC0gZW5yaWNoR08oCiAgZ2VuZSAgICAgICAgICA9IHRhcmdldHMxNTBfZG93biwgIAogIE9yZ0RiICAgICAgICAgPSBvcmcuSHMuZWcuZGIsCiAga2V5VHlwZSAgICAgICA9ICJTWU1CT0wiLAogIG9udCAgICAgICAgICAgPSAiQ0MiLCAKICBwQWRqdXN0TWV0aG9kID0gIkJIIiwKICBxdmFsdWVDdXRvZmYgID0gMC4wNQopCgpHT19lbnJpY2hfdXAxNTBfQ0MgPC0gZW5yaWNoR08oCiAgZ2VuZSAgICAgICAgICA9IHRhcmdldHMxNTBfdXAsICAKICBPcmdEYiAgICAgICAgID0gb3JnLkhzLmVnLmRiLAogIGtleVR5cGUgICAgICAgPSAiU1lNQk9MIiwKICBvbnQgICAgICAgICAgID0gIkNDIiwgCiAgcEFkanVzdE1ldGhvZCA9ICJCSCIsCiAgcXZhbHVlQ3V0b2ZmICA9IDAuMDUKKQpgYGAKCgpgYGB7cn0KcDEgPC0gZG90cGxvdChHT19lbnJpY2hfdXAxNTBfQ0MsIHNob3dDYXRlZ29yeSA9IDIwKSArIAogIGdndGl0bGUoIkdPIEVucmljaG1lbnQgb2YgQ2VsbHVsYXIgQ29tcG9uZW50IGZvciBVcHJlZ3VsYXRlZCBUYXJnZXRzIGluIFZlc2ljbGVzIDE1MCIpICsgCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpCiAgKQoKcDIgPC0gZG90cGxvdChHT19lbnJpY2hfZG93bjE1MF9DQywgc2hvd0NhdGVnb3J5ID0gMjApICsgCiAgZ2d0aXRsZSgiR08gRW5yaWNobWVudCBvZiBDZWxsdWxhciBDb21wb25lbnQgZm9yIERvd25yZWd1bGF0ZWQgVGFyZ2V0cyBpbiBWZXNpY2xlcyAxNTAiKSArIAogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpLAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKQogICkKCnAxICsgcDIKCmNvbWJpbmVkX3Bsb3QgPC0gcDEgKyBwMgoKZ2dzYXZlKCIuL3BpY3R1cmVzL0dPX2VucmljaG1lbnRfZG90cGxvdF9DQ190eXBlMTUwLnRpZmYiLCBwbG90ID0gY29tYmluZWRfcGxvdCwgd2lkdGggPSAxNiwgaGVpZ2h0ID0gMTAsIGRwaSA9IDMwMCkKYGBgCgpgYGB7cn0KR09fZW5yaWNoX1VQMTUwX0NDIDwtIGVucmljaHBsb3Q6OnBhaXJ3aXNlX3Rlcm1zaW0oR09fZW5yaWNoX3VwMTUwX0NDLCBtZXRob2QgPSAiSkMiKQoKcGx0IDwtIGVtYXBwbG90KEdPX2VucmljaF9VUDE1MF9DQywgCiAgICAgICAgIHJlcGVsID0gVFJVRSwKICAgICAgICAgc2hvd0NhdGVnb3J5ID0gMjApICsKICBnZ3RpdGxlKCJBbGwgcHJvY2Vzc2VzIGZvciBVUHJlZ3VsYXRlZCB0YXJnZXRzIGZvciB2ZXNpY2xlcyAxNTAiKSArCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDMpCiAgICApICAgCgpwbHQKCmdnc2F2ZSgiLi9waWN0dXJlcy9HT19lbnJpY2htZW50X2VtYXBwbG90X0NDX3VwX3R5cGUxNTAudGlmZiIsIHBsb3QgPSBwbHQsIHdpZHRoID0gMTYsIGhlaWdodCA9IDEwLCBkcGkgPSAzMDApCmBgYApgYGB7cn0KR09fZW5yaWNoX0RPV04xNTBfQ0MgPC0gZW5yaWNocGxvdDo6cGFpcndpc2VfdGVybXNpbShHT19lbnJpY2hfZG93bjE1MF9DQywgbWV0aG9kID0gIkpDIikKCnBsdCA8LSBlbWFwcGxvdChHT19lbnJpY2hfRE9XTjE1MF9DQywgCiAgICAgICAgIHJlcGVsID0gVFJVRSwKICAgICAgICAgc2hvd0NhdGVnb3J5ID0gMjUpICsKICBnZ3RpdGxlKCJBbGwgcHJvY2Vzc2VzIGZvciBET1dOcmVndWxhdGVkIHRhcmdldHMgZm9yIHZlc2ljbGVzIDE1MCIpICsKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSwKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMykKICAgICkgICAgCgpwbHQKCmdnc2F2ZSgiLi9waWN0dXJlcy9HT19lbnJpY2htZW50X2VtYXBwbG90X0NDX2Rvd25fdHlwZTE1MC50aWZmIiwgcGxvdCA9IHBsdCwgd2lkdGggPSAxNiwgaGVpZ2h0ID0gMTAsIGRwaSA9IDMwMCkKYGBgCgoqKkdPIEVucmljaG1lbnQgb2YgTW9sZWN1bGFyIEZ1bmN0aW9uKioKYGBge3J9CkdPX2VucmljaF9kb3duMTUwX01GIDwtIGVucmljaEdPKAogIGdlbmUgICAgICAgICAgPSB0YXJnZXRzMTUwX2Rvd24sICAKICBPcmdEYiAgICAgICAgID0gb3JnLkhzLmVnLmRiLAogIGtleVR5cGUgICAgICAgPSAiU1lNQk9MIiwKICBvbnQgICAgICAgICAgID0gIk1GIiwgCiAgcEFkanVzdE1ldGhvZCA9ICJCSCIsCiAgcXZhbHVlQ3V0b2ZmICA9IDAuMDUKKQoKR09fZW5yaWNoX3VwMTUwX01GIDwtIGVucmljaEdPKAogIGdlbmUgICAgICAgICAgPSB0YXJnZXRzMTUwX3VwLCAgCiAgT3JnRGIgICAgICAgICA9IG9yZy5Icy5lZy5kYiwKICBrZXlUeXBlICAgICAgID0gIlNZTUJPTCIsCiAgb250ICAgICAgICAgICA9ICJNRiIsIAogIHBBZGp1c3RNZXRob2QgPSAiQkgiLAogIHF2YWx1ZUN1dG9mZiAgPSAwLjA1CikKCnAxIDwtIGRvdHBsb3QoR09fZW5yaWNoX3VwMTUwX01GLCBzaG93Q2F0ZWdvcnkgPSAyMCkgKyAKICBnZ3RpdGxlKCJHTyBFbnJpY2htZW50IG9mIE1vbGVjdWxhciBGdW5jdGlvbiBmb3IgVXByZWd1bGF0ZWQgVGFyZ2V0cyBpbiBWZXNpY2xlcyAxNTAiKSArIAogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpLAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKQogICkKCnAyIDwtIGRvdHBsb3QoR09fZW5yaWNoX2Rvd24xNTBfTUYsIHNob3dDYXRlZ29yeSA9IDIwKSArIAogIGdndGl0bGUoIkdPIEVucmljaG1lbnQgb2YgTW9sZWN1bGFyIEZ1bmN0aW9udCBmb3IgRG93bnJlZ3VsYXRlZCBUYXJnZXRzIGluIFZlc2ljbGVzIDE1MCIpICsgCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpCiAgKQoKcDEgKyBwMgoKY29tYmluZWRfcGxvdCA8LSBwMSArIHAyCgpnZ3NhdmUoIi4vcGljdHVyZXMvR09fZW5yaWNobWVudF9kb3RwbG90X01GX3R5cGUxNTAudGlmZiIsIHBsb3QgPSBjb21iaW5lZF9wbG90LCB3aWR0aCA9IDE2LCBoZWlnaHQgPSAxMCwgZHBpID0gMzAwKQpgYGAKYGBge3J9CkdPX2VucmljaF9VUDE1MF9NRiA8LSBlbnJpY2hwbG90OjpwYWlyd2lzZV90ZXJtc2ltKEdPX2VucmljaF91cDE1MF9NRiwgbWV0aG9kID0gIkpDIikKCnBsdCA8LSBlbWFwcGxvdChHT19lbnJpY2hfVVAxNTBfTUYsIAogICAgICAgICByZXBlbCA9IFRSVUUsCiAgICAgICAgIHNob3dDYXRlZ29yeSA9IDI1KSArCiAgZ2d0aXRsZSgiTW9sZWN1bGFyIEZ1bmN0aW9uIHByb2Nlc3NlcyBmb3IgVVByZWd1bGF0ZWQgdGFyZ2V0cyBmb3IgdmVzaWNsZXMgMTUwIikgKwogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpLAogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAzKQogICAgKSAgIAoKcGx0CgpnZ3NhdmUoIi4vcGljdHVyZXMvR09fZW5yaWNobWVudF9lbWFwcGxvdF9NRl91cF90eXBlMTUwLnRpZmYiLCBwbG90ID0gcGx0LCB3aWR0aCA9IDE2LCBoZWlnaHQgPSAxMCwgZHBpID0gMzAwKQpgYGAKYGBge3J9CkdPX2VucmljaF9ET1dOMTUwX01GIDwtIGVucmljaHBsb3Q6OnBhaXJ3aXNlX3Rlcm1zaW0oR09fZW5yaWNoX2Rvd24xNTBfTUYsIG1ldGhvZCA9ICJKQyIpCgpwbHQgPC0gZW1hcHBsb3QoR09fZW5yaWNoX0RPV04xNTBfTUYsIAogICAgICAgICByZXBlbCA9IFRSVUUsCiAgICAgICAgIHNob3dDYXRlZ29yeSA9IDI1KSArCiAgZ2d0aXRsZSgiTW9sZWN1bGFyIEZ1bmN0aW9uIHByb2Nlc3NlcyBmb3IgRE9XTnJlZ3VsYXRlZCB0YXJnZXRzIGZvciB2ZXNpY2xlcyAxNTAiKSArCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDMpCiAgICApICAgCgpwbHQKCmdnc2F2ZSgiLi9waWN0dXJlcy9HT19lbnJpY2htZW50X2VtYXBwbG90X01GX2Rvd25fdHlwZTE1MC50aWZmIiwgcGxvdCA9IHBsdCwgd2lkdGggPSAxNiwgaGVpZ2h0ID0gMTAsIGRwaSA9IDMwMCkKYGBgCgojIyMg0KLQvtC70YzQutC+INCy0LXQt9C40LrRg9C70Ysg0YLQuNC/0LAgMTYgIyMjCmBgYHtyfQpjb2xkYXRhXzE2IDwtIGNvbGRhdGFbY29sZGF0YSR0eXBlID09IDE2LCBdCnJvd25hbWVzKGNvbGRhdGFfMTYpIDwtIGNvbGRhdGFfMTYkc2FtcGxlCmNvbGRhdGFfMTYKYGBgCmBgYHtyfQpjb21tb25fc2FtcGxlc18xNiA8LSBpbnRlcnNlY3QoY29sbmFtZXMoY291bnRzKSwgY29sZGF0YV8xNiRzYW1wbGVzKQoKY291bnRzXzE2IDwtIGNvdW50c1ssIGMoY291bnRzJG1pUk5BLCBjb21tb25fc2FtcGxlcyldICAKY291bnRzXzE2IDwtIGNvdW50c18xNlssIHJvd25hbWVzKGNvbGRhdGFfMTYpXSAj0YDQsNC90LbQuNGA0YPRjiDQv9C+INC60L7Qu9C+0L3QutC4INCyIGNvdW50cyDRgtCw0Log0LbQtSDQutCw0Log0Lgg0L3QsNC30LLQsNC90LjRjyDRgdGC0YDQvtC6INCyIGNvbGRhdGFfMTUwCmhlYWQoY291bnRzXzE2KQpgYGAKKirQodC+0LfQtNCw0LXQvCBERVNlcURhdGFTZXQg0LjQtyDQvNCw0YLRgNC40YbRiyDQutCw0YPQvdGC0L7QsioqCmBgYHtyfQpkZHNfMTYgPC0gREVTZXFEYXRhU2V0RnJvbU1hdHJpeChjb3VudERhdGEgPSBjb3VudHNfMTYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xEYXRhID0gY29sZGF0YV8xNiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2lnbiA9IH4gMCArIHBhdGllbnQgKyBjb25kaXRpb24pCmRkc18xNiRjb25kaXRpb24gPC0gcmVsZXZlbChkZHNfMTYkY29uZGl0aW9uLCByZWYgPSAiYmVmb3JlIikKZGRzXzE2CmBgYAoqKtCk0LjQu9GM0YLRgNCw0YbQuNGPKioKYGBge3J9CmRpbShkZHNfMTYpCnNtYWxsZXN0R3JvdXBTaXplIDwtIDMKa2VlcCA8LSByb3dTdW1zKGNvdW50cyhkZHNfMTYpID49IDEwKSA+PSBzbWFsbGVzdEdyb3VwU2l6ZQpkZHNfMTYgPC0gZGRzXzE2W2tlZXAsXQpkaW0oZGRzXzE2KQpgYGAKCioqUnVuIERpZmZlcmVudGlhbCBFeHByZXNzaW9uIEFuYWx5c2lzIGZvciAxNTAgdHlwZSoqCmBgYHtyfQpkZHNfMTYgPC0gREVTZXEoZGRzXzE2LCBmaXRUeXBlID0gInBhcmFtZXRyaWMiKQpgYGAKCmBgYHtyfQpwbG90RGlzcEVzdHMoZGRzXzE2KQpgYGAKYGBge3J9CnJlc18xNiA8LSByZXN1bHRzKGRkc18xNiwgY29udHJhc3Q9YygiY29uZGl0aW9uIiwgImJlZm9yZSIsICJhZnRlciIpKQpyZXNfMTYKYGBgCioqTUEgcGxvdCoqCgrQpNC40LvRjNGC0YDQsNGG0LjRjyDRgtC+0YfQtdC6INGBINC90LjQt9C60LjQvCDRgdGA0LXQtNC90LjQvCDRjdC60YHQv9GA0LXRgdGB0LjRgNC+0LLQsNC90LjQtdC8ICjQv9C+IGJhc2VNZWFuKS4KCeKAognQntCx0YvRh9C90L4g0L7RgtGB0LXQutCw0Y7RgtGB0Y8gYmFzZU1lYW4gPCAxLgoJMi4J0J7Qv9GA0LXQtNC10LvQtdC90LjQtSDQt9C90LDRh9C40LzRi9GFINCz0LXQvdC+0LIgKNGB0LjQvdC40LUg0YLQvtGH0LrQuCk6CgnigKIJ0JjRgdC/0L7Qu9GM0LfRg9C10YLRgdGPINC60YDQuNGC0LXRgNC40LkgcGFkaiA8IDAuMSDQv9C+INGD0LzQvtC70YfQsNC90LjRjiwg0LAg0L3QtSA8IDAuMDUhIApgYGB7cn0KdGlmZigiLi9waWN0dXJlcy9QbG90TUFfc3RhbmRhcnRfcGFkal8wLjA1X3R5cGUxNi50aWZmIiwgCiAgICAgd2lkdGggPSA4LCBoZWlnaHQgPSA2LCB1bml0cyA9ICJpbiIsIHJlcyA9IDMwMCwgYmcgPSAid2hpdGUiKQpwbG90TUEocmVzXzE2LCBhbHBoYSA9IDAuMDUsIHlsaW0gPSBjKC04LCA4KSkgCmRldi5vZmYoKQpwbG90TUEocmVzXzE2LCBhbHBoYSA9IDAuMDUsIHlsaW0gPSBjKC04LCA4KSkgCmBgYAoqKtCa0LDRgdGC0L7QvNC90YvQuSBNQSBwbG90INC/0L4gcC12YWx1ZSoqCmBgYHtyfQpyZXNfZGYgPC0gcmVzXzE2ICU+JQogIGFzLmRhdGEuZnJhbWUgJT4lCiAgbXV0YXRlKGNvbG9yID0gY2FzZV93aGVuKCAKICAgIHB2YWx1ZSA8IDAuMDUgJiAhaXMubmEocHZhbHVlKSAmIGFicyhsb2cyRm9sZENoYW5nZSkgPiAxICB+ICJibHVlIiwgICMg0JfQvdCw0YfQuNC80YvQtSDQv9C+IHAtdmFsdWUg0Lgg0LTQuNGEINGN0LrRgdC/0YDQtdGB0YHQuNGA0L7QstCw0L3QvdGL0LUKICAgIFRSVUUgfiAiZ3JheTcwIgogICkpCgpwbHQgPC0gZ2dwbG90KHJlc19kZiwgYWVzKHggPSBiYXNlTWVhbiwgeSA9IGxvZzJGb2xkQ2hhbmdlLCBjb2xvciA9IGNvbG9yKSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjcsIHNpemUgPSAxKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAic29saWQiLCBjb2xvciA9ICJncmF5NDAiLCBzaXplID0gMS41KSArICAjINCU0L7QsdCw0LLQu9GP0LXQvCDQu9C40L3QuNGOCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoImdyYXk3MCIgPSAiZ3JheTcwIiwgImJsdWUiID0gImJsdWUiKSkgKwogIHNjYWxlX3hfbG9nMTAobGFiZWxzID0gc2NhbGVzOjpzY2llbnRpZmljKSArIAogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyh4ID0gIm1lYW4gb2Ygbm9ybWFsaXplZCBjb3VudHMiLCB5ID0gImxvZyBmb2xkIGNoYW5nZSIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgpwbHQKZ2dzYXZlKCIuL3BpY3R1cmVzL1Bsb3RNQV9jYXN0b21fcHZhbHVlMC4wNV90eXBlMTYudGlmZiIsIHBsb3QgPSBwbHQsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNiwgZHBpID0gMzAwLCBiZyA9ICJ3aGl0ZSIpCmBgYAoqKtCX0L3QsNGH0LjQvNGL0LUg0YDQtdC30YPQu9GM0YLQsNGC0YsqKgpgYGB7cn0Kc3VtbWFyeShyZXN1bHRzKGRkc18xNiwgY29udHJhc3Q9YygiY29uZGl0aW9uIiwgImJlZm9yZSIsICJhZnRlciIpLCBhbHBoYT0wLjA1KSkKYGBgCkxldCdzIGFycmFuZ2VkIGl0IGJ5IGxvZzJGb2xkQ2hhbmdlOgpgYGB7cn0Kb3JkZXJfaW5kaWNlcyA8LSBvcmRlcigtcmVzXzE2JGxvZzJGb2xkQ2hhbmdlKQpyZXNfMTZbb3JkZXJfaW5kaWNlcywgXQpgYGAKVmlzdWFsaXNhdGlvbiBmb3IgdGhlIGZpcnN0IGdlbmUKYGBge3J9CiNwbG90Q291bnRzKGRkc18xNiwgZ2VuZT13aGljaC5tYXgocmVzXzE2JGxvZzJGb2xkQ2hhbmdlKSwgaW50Z3JvdXA9ImNvbmRpdGlvbiIpCnBsb3RDb3VudHMoZGRzXzE2LCBnZW5lPXdoaWNoLm1pbihyZXNfMTYkcHZhbHVlKSwgaW50Z3JvdXA9ImNvbmRpdGlvbiIpCiNwbG90Q291bnRzKGRkcywgZ2VuZT1yb3duYW1lcyhyZXMpW3doaWNoLm1pbihyZXMkcGFkalt3aGljaC5tYXgocmVzJGxvZzJGb2xkQ2hhbmdlKV0pXSwgaW50Z3JvdXA9ImNvbmRpdGlvbiIpCmBgYAoqKlZvbGNhbm8gcGxvdCoqCmBgYHtyfQpwbHQgPC0gRW5oYW5jZWRWb2xjYW5vKHJlc18xNiwKICAgICAgICAgICAgICAgIGxhYiA9IHJvd25hbWVzKHJlc18xNiksCiAgICAgICAgICAgICAgICB4ID0gImxvZzJGb2xkQ2hhbmdlIiwKICAgICAgICAgICAgICAgIHkgPSAicHZhbHVlIiwKICAgICAgICAgICAgICAgIHBDdXRvZmYgPSAwLjA1LAogICAgICAgICAgICAgICAgRkNjdXRvZmYgPSAxLAogICAgICAgICAgICAgICAgbGFiU2l6ZSA9IDMuMCwKICAgICAgICAgICAgICAgIGJveGVkTGFiZWxzID0gRkFMU0UsCiAgICAgICAgICAgICAgICBjb2wgPSBjKCdibGFjaycsICcjQ0JENUU4JywgJyNCM0UyQ0QnLCAnI0ZEQ0RBQycpLAogICAgICAgICAgICAgICAgY29sQWxwaGEgPSAxLAogICAgICAgICAgICAgICAgdGl0bGUgPSBOVUxMLCAgICAgICAgCiAgICAgICAgICAgICAgICBzdWJ0aXRsZSA9IE5VTEwpIAoKcGx0Cmdnc2F2ZSgiLi9waWN0dXJlcy9Wb2xjYW5vIHBsb3RfYmFzZWRfb25fUHZhbHVlXzE2dHlwZS50aWZmIiwgcGxvdCA9IHBsdCwgd2lkdGggPSA4LCBoZWlnaHQgPSA2LCBkcGkgPSAzMDAsIGJnID0gIndoaXRlIikKYGBgCioqcmxvZyDRgtGA0LDQvdGB0YTQvtGA0LzQsNGG0LjRjyoqCgnigKIJ0KfQtdGA0L3Ri9C1INGC0L7Rh9C60Lgg4oCTINGB0YLQsNC90LTQsNGA0YLQvdC+0LUg0L7RgtC60LvQvtC90LXQvdC40LUg0L7RgtC00LXQu9GM0L3Ri9GFINCz0LXQvdC+0LIuCgnigKIJ0JrRgNCw0YHQvdCw0Y8g0LvQuNC90LjRjyDigJMg0YHQs9C70LDQttC10L3QvdGL0Lkg0YLRgNC10L3QtCDQt9Cw0LLQuNGB0LjQvNC+0YHRgtC4IFNEINC+0YIg0YHRgNC10LTQvdC10LPQviDQt9C90LDRh9C10L3QuNGPINGN0LrRgdC/0YDQtdGB0YHQuNC4LgoJ4oCiCdCV0YHQu9C4INC60YDQsNGB0L3QsNGPINC70LjQvdC40Y8g0L3QsNC60LvQvtC90LXQvdCwINCy0LLQtdGA0YUg4oaSINGB0YLQsNC90LTQsNGA0YLQvdC+0LUg0L7RgtC60LvQvtC90LXQvdC40LUg0YDQsNGB0YLRkdGCINGBINGD0LLQtdC70LjRh9C10L3QuNC10Lwg0YHRgNC10LTQvdC10LPQviAo0L/Qu9C+0YXQsNGPINC90L7RgNC80LDQu9C40LfQsNGG0LjRjykuCgnigKIJ0JXRgdC70Lgg0LrRgNCw0YHQvdCw0Y8g0LvQuNC90LjRjyDQv9GA0LjQvNC10YDQvdC+INCz0L7RgNC40LfQvtC90YLQsNC70YzQvdCwIOKGkiDQvdC+0YDQvNCw0LvQuNC30LDRhtC40Y8g0YHRgNCw0LHQvtGC0LDQu9CwINGF0L7RgNC+0YjQvi4KYGBge3J9CnJsdF8xNiA8LSBybG9nKGRkc18xNikgCm1lYW5TZFBsb3QoYXNzYXkocmx0XzE2KSkgICPQv9C+0LrQsNC30YvQstCw0LXRgiwg0LrQsNC6INC40LfQvNC10L3Rj9C10YLRgdGPINGB0YLQsNC90LTQsNGA0YLQvdC+0LUg0L7RgtC60LvQvtC90LXQvdC40LUg0LIg0LfQsNCy0LjRgdC40LzQvtGB0YLQuCDQvtGCINGB0YDQtdC00L3QtdCz0L4g0LfQvdCw0YfQtdC90LjRjyDRjdC60YHQv9GA0LXRgdGB0LjQuC4KYGBgCmBgYHtyfQpwY2FEYXRhIDwtIHBsb3RQQ0Eocmx0XzE2LCBpbnRncm91cD1jKCJjb25kaXRpb24iLCAicGF0aWVudCIpLCByZXR1cm5EYXRhID0gVFJVRSkKcGVyY2VudFZhciA8LSByb3VuZCgxMDAgKiBhdHRyKHBjYURhdGEsICJwZXJjZW50VmFyIikpCgpnZ3Bsb3QocGNhRGF0YSwgYWVzKFBDMSwgUEMyLCBzaGFwZSA9IHBhdGllbnQsIGNvbG9yID0gY29uZGl0aW9uKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDMpICsKICB4bGFiKHBhc3RlMCgiUEMxOiAiLCBwZXJjZW50VmFyWzFdLCAiJSIpKSArCiAgeWxhYihwYXN0ZTAoIlBDMjogIiwgcGVyY2VudFZhclsyXSwgIiUiKSkgKyAKICBjb29yZF9maXhlZCgpICsKICB0aGVtZV9idygpICsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQyIikKYGBgCmBgYHtyfQphc3NheShybHRfMTYpIDwtIGxpbW1hOjpyZW1vdmVCYXRjaEVmZmVjdChhc3NheShybHRfMTYpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYXRjaCA9IGNvbERhdGEoZGRzXzE2KVssJ3BhdGllbnQnXSkKCnBjYURhdGEgPC0gcGxvdFBDQShybHRfMTYsIGludGdyb3VwPWMoImNvbmRpdGlvbiIsICJwYXRpZW50IiksIHJldHVybkRhdGEgPSBUUlVFKQpwZXJjZW50VmFyIDwtIHJvdW5kKDEwMCAqIGF0dHIocGNhRGF0YSwgInBlcmNlbnRWYXIiKSkKCnBsdCA8LSBnZ3Bsb3QocGNhRGF0YSwgYWVzKFBDMSwgUEMyLCBzaGFwZSA9IHBhdGllbnQsIGNvbG9yID0gY29uZGl0aW9uKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDMpICsKICB4bGFiKHBhc3RlMCgiUEMxOiAiLCBwZXJjZW50VmFyWzFdLCAiJSIpKSArCiAgeWxhYihwYXN0ZTAoIlBDMjogIiwgcGVyY2VudFZhclsyXSwgIiUiKSkgKyAKICBjb29yZF9maXhlZCgpICsKICB0aGVtZV9idygpICsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQyIikKCnBsdApnZ3NhdmUoIi4vcGljdHVyZXMvUENBIHBsb3QgZm9yIHR5cGUgMTYgYWZ0ZXIgcmVtb3ZpbmcgZG9ub3IgZWZmZWN0LnRpZmYiLCBwbG90ID0gcGx0LCB3aWR0aCA9IDgsIGhlaWdodCA9IDYsIGRwaSA9IDMwMCwgYmcgPSAid2hpdGUiKQpgYGAKKipQbG90IGEgaGVhdG1hcCBvZiB0aGUgbW9zdCBleHByZXNzZWQgZ2VuZXMqKgoKYGBge3J9CnJlc19zaWduXzE2IDwtIHN1YnNldChyZXNfMTYsIHB2YWx1ZSA8IDAuMDUgJiAhaXMubmEocHZhbHVlKSAmIGFicyhsb2cyRm9sZENoYW5nZSkgPiAxLjApCnJlc19zaWduXzE2IDwtIHJlc19zaWduXzE2W29yZGVyKHJlc19zaWduXzE2JGxvZzJGb2xkQ2hhbmdlLCBkZWNyZWFzaW5nID0gVFJVRSksIF0KCnNpZ19nZW5lcyA8LSByb3duYW1lcyhyZXNfc2lnbl8xNikgICMg0J/QvtC70YPRh9Cw0LXQvCDQuNC80LXQvdCwINCz0LXQvdC+0LIsINC60L7RgtC+0YDRi9C1INC/0YDQvtGI0LvQuCDRhNC40LvRjNGC0YDQsNGG0LjRjgoKZGVfbWF0IDwtIGFzc2F5KHJsdF8xNilbc2lnX2dlbmVzLCBdIApkYXRhbWF0cml4IDwtIGRlX21hdAojZGF0YW1hdHJpeCA8LSB0KHNjYWxlKHQoZGVfbWF0KSkpCgphbm5vdGF0aW9uX2NvbCA8LSBkYXRhLmZyYW1lKGNvbmRpdGlvbiA9IGNvbGRhdGFfMTYkY29uZGl0aW9uKQpyb3duYW1lcyhhbm5vdGF0aW9uX2NvbCkgPC0gY29sbmFtZXMoZGF0YW1hdHJpeCkKCmFubm90YXRpb25fY29sb3JzIDwtIGxpc3QoCiAgY29uZGl0aW9uID0gYygiYmVmb3JlIiA9ICIjRkZDQzAwIiwgImFmdGVyIiA9ICIjMzM5OUZGIikKKQoKcGx0IDwtIHBoZWF0bWFwKGRhdGFtYXRyaXgsIAogICAgICAgICBjbHVzdGVyX3Jvd3MgPSBUUlVFLCAKICAgICAgICAgc2hvd19yb3duYW1lcyA9IFRSVUUsIAogICAgICAgICBjbHVzdGVyX2NvbHMgPSBUUlVFLCAKICAgICAgICAgYW5ub3RhdGlvbl9jb2wgPSBhbm5vdGF0aW9uX2NvbCwKICAgICAgICAgYW5ub3RhdGlvbl9jb2xvcnMgPSBhbm5vdGF0aW9uX2NvbG9ycywKICAgICAgICAgZGlzcGxheV9udW1iZXJzID0gVFJVRSwKICAgICAgICAgbGVnZW5kID0gRkFMU0UsCiAgICAgICAgIGZvbnRzaXplID0gMTUpICAKCnBsdApnZ3NhdmUoIi4vcGljdHVyZXMvSGVhdG1hcCBvZiBkaWZmIGV4cHJlc3NlZCBnZW5lc190eXBlMTYudGlmZiIsIHBsb3QgPSBwbHQsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNiwgZHBpID0gMzAwLCBiZyA9ICJ3aGl0ZSIpCmBgYAoqKlBsb3Qgb2YgdGhlIGRpc3RhbmNlIGJldHdlZW4gc2FtcGxlcyBoZWF0bWFwKioK0KDQsNGB0YfQtdGCINGA0LDRgdGB0YLQvtGP0L3QuNC5INC80LXQttC00YMg0L7QsdGA0LDQt9GG0LDQvNC4CgnigKIJ0J7QsdGL0YfQvdC+INC40YHQv9C+0LvRjNC30YPQtdGC0YHRjyDQtdCy0LrQu9C40LTQvtCy0L4g0YDQsNGB0YHRgtC+0Y/QvdC40LUgKNC/0L4g0YPQvNC+0LvRh9Cw0L3QuNGOINCyIERFU2VxMikuCgnigKIJ0J7QvdC+INCy0YvRh9C40YHQu9GP0LXRgtGB0Y8g0L/QviDQvdC+0YDQvNCw0LvQuNC30L7QstCw0L3QvdGL0Lwg0LTQsNC90L3Ri9C8INGN0LrRgdC/0YDQtdGB0YHQuNC4IChybG9nKCkg0LjQu9C4IHZzdCgpKS4KCeKAognQp9C10Lwg0LzQtdC90YzRiNC1INGA0LDRgdGB0YLQvtGP0L3QuNC1IOKAlCDRgtC10Lwg0LHQvtC70LXQtSDQv9C+0YXQvtC20Lgg0L7QsdGA0LDQt9GG0YsuCgpgYGB7cn0Kc2FtcGxlRGlzdHNfMTYgPC0gZGlzdCh0KGFzc2F5KHJsdF8xNikpKQpzYW1wbGVEaXN0TWF0cml4XzE2IDwtIGFzLm1hdHJpeChzYW1wbGVEaXN0c18xNikKcm93bmFtZXMoc2FtcGxlRGlzdE1hdHJpeF8xNikgPC0gcGFzdGUocmx0XzE2JGNvbmRpdGlvbiwgcmx0XzE2JHBhdGllbnQsIHNlcD0iX3BhdGllbnQiKQpjb2xuYW1lcyhzYW1wbGVEaXN0TWF0cml4XzE2KSA8LSBwYXN0ZShybHRfMTYkY29uZGl0aW9uLCBybHRfMTYkcGF0aWVudCwgc2VwPSJfcGF0aWVudCIpCgpwbHQgPC0gcGhlYXRtYXAoc2FtcGxlRGlzdE1hdHJpeF8xNiwKICAgICAgICAgY2x1c3RlcmluZ19kaXN0YW5jZV9yb3dzID0gImV1Y2xpZGVhbiIsCiAgICAgICAgIGNsdXN0ZXJpbmdfZGlzdGFuY2VfY29scyA9ICJldWNsaWRlYW4iLAogICAgICAgICBmb250c2l6ZSA9IDEyLAogICAgICAgICBsZWdlbmQgPSBGQUxTRSwKICAgICAgICAgZGlzcGxheV9udW1iZXJzID0gVFJVRSwKICAgICAgICAgY29sb3IgPSBjb2xvcnMpCgpwbHQKZ2dzYXZlKCIuL3BpY3R1cmVzL1Bsb3Qgb2YgdGhlIGRpc3RhbmNlIGJldHdlZW4gc2FtcGxlc190eXBlMTYudGlmZiIsIHBsb3QgPSBwbHQsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNiwgZHBpID0gMzAwLCBiZyA9ICJ3aGl0ZSIpCmBgYAojIyMg0JDQvdCw0LvQuNC3INC+0LHQvtCz0LDRidC10L3QuNGPINC00LvRjyDQstC10LfQuNC60YPQuyDRgtC40L/QsCAxNiAjIyMKYGBge3J9CnVwXzE2IDwtIHJlc19zaWduXzE2ICU+JSAKICBhcy5kYXRhLmZyYW1lKCkgJT4lIAogIGZpbHRlcihsb2cyRm9sZENoYW5nZSA+IDApCmRvd25fMTYgPC0gcmVzX3NpZ25fMTYgJT4lIAogIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgZmlsdGVyKGxvZzJGb2xkQ2hhbmdlIDwgMCkKcm93bmFtZXModXBfMTYpCnJvd25hbWVzKGRvd25fMTYpCmBgYArQn9C10YDQtdCy0L7QtNC40Lwg0LIgbWlSQmFzZQoJ4oCiCW1pUkJhc2U6IGh0dHBzOi8vd3d3Lm1pcmJhc2Uub3JnLwoJ4oCiCU1pckdlbmVEQjogaHR0cHM6Ly9taXJnZW5lZGIub3JnLwpgYGB7cn0KdXJsIDwtICJodHRwczovL21pcmdlbmVkYi5vcmcvYnJvd3NlL2hzYSIKcGFnZSA8LSByZWFkX2h0bWwodXJsKQpgYGAKCtCf0LDRgNGB0LjQvCDRgtCw0LHQu9C40YbRgwpgYGB7cn0KbWlyX3RhYmxlIDwtIHBhZ2UgJT4lCiAgaHRtbF9lbGVtZW50KCJ0YWJsZSIpICU+JQogIGh0bWxfdGFibGUoZmlsbCA9IFRSVUUpIAoKbWlyX3RhYmxlIDwtIG1pcl90YWJsZVstYygxOjMpLCBjKDEsMikgXSAKY29sbmFtZXMobWlyX3RhYmxlKSA8LSBjKCJNaXJHZW5lREJfSUQiLCAiTWlSQmFzZV9JRCIpCm1pcl90YWJsZSRNaXJHZW5lREJfSUQgPC0gc3ViKCIgViIsICIiLCBtaXJfdGFibGUkTWlyR2VuZURCX0lEKQoKaGVhZChtaXJfdGFibGUpCmBgYAoKYGBge3J9CnVwXzE2X2NsZWFuIDwtIHN1YigiXy4qIiwgIiIsIHJvdy5uYW1lcyh1cF8xNikpCnVwXzE2X2NvbnZlcnRlZCA8LSBtaXJfdGFibGUkTWlSQmFzZV9JRFttYXRjaCh1cF8xNl9jbGVhbiwgbWlyX3RhYmxlJE1pckdlbmVEQl9JRCldCgpkb3duXzE2X2NsZWFuIDwtIHN1YigiXy4qIiwgIiIsIHJvdy5uYW1lcyhkb3duXzE2KSkKZG93bl8xNl9jb252ZXJ0ZWQgPC0gbWlyX3RhYmxlJE1pUkJhc2VfSURbbWF0Y2goZG93bl8xNl9jbGVhbiwgbWlyX3RhYmxlJE1pckdlbmVEQl9JRCldCnVwXzE2X2NvbnZlcnRlZApkb3duXzE2X2NvbnZlcnRlZApgYGAKCioq0JrQvtC90LLQtdGA0YLQsNGG0LjRjyDQsiBNSU1BVElEKiogCtCyINC40YLQvtCz0LUg0LfQsNC80LXQvdC40LvQsCBOQSDQstGA0YPRh9C90YPRjiDQvdCwINGB0LDQvNGL0LUg0LHQu9C40LfQutC40LUsINC90L4g0Y3RgtC+INGC0LDQutCw0Y8g0YHQtdCx0LUg0L/RgNCw0LrRgtC40LrQsAoKTkEgSHNhLU1pci0xMC1QM2FfNXAgINC10YHRgtGMINC00LLQsCDRgdC+0L7RgtCy0LXRgtGB0YLQstC40Y86CkhzYS1NaXItMTAtUDFjID0JaHNhLW1pci0xMGEKSHNhLU1pci0xMC1QM2IgPSBoc2EtbWlyLTEyNWEKCk5BIEhzYS1NaXItMTI2XzNwKiDQtdGB0YLRjCDQvtC00L3QviDRgdC+0L7RgtCy0LXRgtGB0YLQstC40LU6IApIc2EtTWlyLTEyNi1QMiA9IGhzYS1taXItMTI2IAoKTkEgSHNhLU1pci0zMC1QMWNfM3AqINC10YHRgtGMINGC0YDQuCDRgdC+0L7RgtCy0LXRgtGB0YLQstC40Y86CkhzYS1NaXItMzAtUDFhID0gaHNhLW1pci0zMGQKSHNhLU1pci0zMC1QMWIgPSBoc2EtbWlyLTMwYQpIc2EtTWlyLTMwLVAxZCA9IGhzYS1taXItMzBlCgpbMV0gIkhzYS1NaXItMTg1XzVwIiAgICAgIkhzYS1NaXItMTk3XzNwIiAgICAgIkhzYS1NaXItMTAtUDNhXzVwIiAgIkhzYS1NaXItMTQ4LVAzXzVwKiIgIkhzYS1NaXItMzAtUDFhXzNwKiIgIkhzYS1NaXItMTUwXzNwKiIgICAKWzddICJIc2EtTWlyLTM2MV8zcCoiICAgICJIc2EtTWlyLTEwLVAyYl81cCIgICJIc2EtTWlyLTEyNl8zcCoiICAgClsxXSAiSHNhLU1pci0zNDBfNXAiICAgICAiSHNhLU1pci0xODEtUDJjXzVwIiAiSHNhLU1pci0yMjNfNXAqIiAgICAiSHNhLU1pci0zMC1QMWNfM3AqIgoKTUkgKE1pY3JvUk5BIEdlbmUgSUQpIOKAlCDRjdGC0L4g0LjQtNC10L3RgtC40YTQuNC60LDRgtC+0YAg0L/RgNC10LTRiNC10YHRgtCy0LXQvdC90LjQutCwIChwcmVjdXJzb3IpIG1pUk5BCk1JTUFUIChNYXR1cmUgbWlSTkEgSUQpIOKAlCDRjdGC0L4g0LjQtNC10L3RgtC40YTQuNC60LDRgtC+0YAg0LfRgNC10LvQvtC5IChtYXR1cmUpIG1pUk5BLCDQutC+0YLQvtGA0LDRjyDRhNGD0L3QutGG0LjQvtC90LjRgNGD0LXRgiDQsiDQutC70LXRgtC60LUKYGBge3J9CnVwXzE2X2NvbnZlcnRlZCA8LSAgYygiaHNhLW1pUi0xODUtNXAiLCAiaHNhLW1pUi0xOTctM3AiLCAiaHNhLW1pUi0xNTItNXAiLCAiaHNhLW1pUi0zMGQtM3AiLCAiaHNhLW1pUi0xNTAtM3AiLCAiaHNhLW1pUi0zNjEtM3AiLCAiaHNhLW1pUi05OWItNXAiLCAiaHNhLW1pUi0xMjYtM3AiKQpkb3duXzE2X2NvbnZlcnRlZCA8LSBjKCJoc2EtbWlSLTM0MC01cCIsICJoc2EtbWlSLTE4MWQtNXAiLCAiaHNhLW1pUi0yMjMtNXAiKQoKCmNvbnZlcnRlZF9taXJuYV91cDE2IDwtIG1pUk5BVmVyc2lvbkNvbnZlcnQodXBfMTZfY29udmVydGVkKQpjb252ZXJ0ZWRfbWlybmFfZG93bjE2IDwtIG1pUk5BVmVyc2lvbkNvbnZlcnQoZG93bl8xNl9jb252ZXJ0ZWQpCmNvbnZlcnRlZF9taXJuYV91cDE2CmNvbnZlcnRlZF9taXJuYV9kb3duMTYKYGBgCioq0JfQsNC/0YDQvtGBINGC0LDRgNCz0LXRgtC+0LIg0LjQtyDQsdCw0LfRiyBtdWx0aU1pUioqCmBgYHtyfQp0YXJnZXRzMTZfdXAgPC0gdW5pcXVlKGdldF9tdWx0aW1pcihvcmcgPSAiaHNhIiwgbWlybmEgPSBjb252ZXJ0ZWRfbWlybmFfdXAxNiRBY2Nlc3Npb24sIHRhYmxlID0gInZhbGlkYXRlZCIpQGRhdGEkdGFyZ2V0X3N5bWJvbCkKYGBgCmBgYHtyfQp0YXJnZXRzMTZfZG93biA8LSB1bmlxdWUoZ2V0X211bHRpbWlyKG9yZyA9ICJoc2EiLCBtaXJuYSA9IGNvbnZlcnRlZF9taXJuYV9kb3duMTYkQWNjZXNzaW9uLCB0YWJsZSA9ICJ2YWxpZGF0ZWQiKUBkYXRhJHRhcmdldF9zeW1ib2wpCmBgYAoqKtCQ0L3QsNC70LjQtyDQvtCx0L7Qs9Cw0YnQtdC90LjRjywg0YHQstGP0LfQsNC90L3Ri9C5INGB0L4gQmlvbG9naWNhbCBQcm9jZXNzKioKYGBge3J9CkdPX2VucmljaF91cDE2X2JwIDwtIGVucmljaEdPKAogIGdlbmUgICAgICAgICAgPSB0YXJnZXRzMTZfdXAsICAKICBPcmdEYiAgICAgICAgID0gb3JnLkhzLmVnLmRiLAogIGtleVR5cGUgICAgICAgPSAiU1lNQk9MIiwKICBvbnQgICAgICAgICAgID0gIkJQIiwgCiAgcEFkanVzdE1ldGhvZCA9ICJCSCIsCiAgcXZhbHVlQ3V0b2ZmICA9IDAuMDUKKQoKR09fZW5yaWNoX2Rvd24xNl9icCA8LSBlbnJpY2hHTygKICBnZW5lICAgICAgICAgID0gdGFyZ2V0czE2X2Rvd24sICAKICBPcmdEYiAgICAgICAgID0gb3JnLkhzLmVnLmRiLAogIGtleVR5cGUgICAgICAgPSAiU1lNQk9MIiwKICBvbnQgICAgICAgICAgID0gIkJQIiwgCiAgcEFkanVzdE1ldGhvZCA9ICJCSCIsCiAgcXZhbHVlQ3V0b2ZmICA9IDAuMDUKKQpgYGAKCmBgYHtyfQpwMSA8LSBkb3RwbG90KEdPX2VucmljaF91cDE2X2JwLCBzaG93Q2F0ZWdvcnkgPSAyMCkgKyAKICBnZ3RpdGxlKCJCUCBmb3IgVXByZWd1bGF0ZWQgVGFyZ2V0cyBpbiBWZXNpY2xlcyAxNiIpICsgCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpCiAgKQoKcDIgPC0gZG90cGxvdChHT19lbnJpY2hfZG93bjE2X2JwLCBzaG93Q2F0ZWdvcnkgPSAyMCkgKyAKICBnZ3RpdGxlKCJCUCBmb3IgRG93bnJlZ3VsYXRlZCBUYXJnZXRzIGluIFZlc2ljbGVzIDE2IikgKyAKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikKICApCmNvbWJpbmVkX3Bsb3QgPC0gcDEgKyBwMgpjb21iaW5lZF9wbG90Cmdnc2F2ZSgiLi9waWN0dXJlcy9HT19lbnJpY2htZW50X2RvdHBsb3RfQlBfdHlwZTE2LnRpZmYiLCBwbG90ID0gY29tYmluZWRfcGxvdCwgd2lkdGggPSAxNiwgaGVpZ2h0ID0gMTAsIGRwaSA9IDMwMCkKYGBgCgpgYGB7cn0KR09fZW5yaWNoX1VQMTZfQlAgPC0gZW5yaWNocGxvdDo6cGFpcndpc2VfdGVybXNpbShHT19lbnJpY2hfdXAxNl9icCwgbWV0aG9kID0gIkpDIikKCnBsdCA8LSBlbWFwcGxvdChHT19lbnJpY2hfVVAxNl9CUCwgCiAgICAgICAgIHJlcGVsID0gVFJVRSwKICAgICAgICAgc2hvd0NhdGVnb3J5ID0gMjApICsKICBnZ3RpdGxlKCJCUCBmb3IgVVByZWd1bGF0ZWQgdGFyZ2V0cyBmb3IgdmVzaWNsZXMgMTYiKSArCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDMpCiAgICApICAgCgpwbHQKCmdnc2F2ZSgiLi9waWN0dXJlcy9HT19lbnJpY2htZW50X2VtYXBwbG90X0JQX3VwX3R5cGUxNi50aWZmIiwgcGxvdCA9IHBsdCwgd2lkdGggPSAxNiwgaGVpZ2h0ID0gMTAsIGRwaSA9IDMwMCkKYGBgCmBgYHtyfQpHT19lbnJpY2hfRE9XTjE2X2FsbCA8LSBlbnJpY2hwbG90OjpwYWlyd2lzZV90ZXJtc2ltKEdPX2VucmljaF9kb3duMTZfYWxsLCBtZXRob2QgPSAiSkMiKQoKcGx0IDwtIGVtYXBwbG90KEdPX2VucmljaF9ET1dOMTZfYWxsLCAKICAgICAgICAgcmVwZWwgPSBUUlVFLAogICAgICAgICBzaG93Q2F0ZWdvcnkgPSAyMCkgKwogIGdndGl0bGUoIkJQIGZvciBET1dOcmVndWxhdGVkIHRhcmdldHMgZm9yIHZlc2ljbGVzIDE2IikgKwogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpLAogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAzKQogICAgKSAgICAKCnBsdAoKZ2dzYXZlKCIuL3BpY3R1cmVzL0dPX2VucmljaG1lbnRfZW1hcHBsb3RfQlBfZG93bl90eXBlMTYudGlmZiIsIHBsb3QgPSBwbHQsIHdpZHRoID0gMTYsIGhlaWdodCA9IDEwLCBkcGkgPSAzMDApCmBgYAoqKkdPIEVucmljaG1lbnQgb2YgQ2VsbHVsYXIgQ29tcG9uZW50KioKYGBge3J9CkdPX2VucmljaF9kb3duMTZfQ0MgPC0gZW5yaWNoR08oCiAgZ2VuZSAgICAgICAgICA9IHRhcmdldHMxNl9kb3duLCAgCiAgT3JnRGIgICAgICAgICA9IG9yZy5Icy5lZy5kYiwKICBrZXlUeXBlICAgICAgID0gIlNZTUJPTCIsCiAgb250ICAgICAgICAgICA9ICJDQyIsIAogIHBBZGp1c3RNZXRob2QgPSAiQkgiLAogIHF2YWx1ZUN1dG9mZiAgPSAwLjA1CikKCkdPX2VucmljaF91cDE2X0NDIDwtIGVucmljaEdPKAogIGdlbmUgICAgICAgICAgPSB0YXJnZXRzMTZfdXAsICAKICBPcmdEYiAgICAgICAgID0gb3JnLkhzLmVnLmRiLAogIGtleVR5cGUgICAgICAgPSAiU1lNQk9MIiwKICBvbnQgICAgICAgICAgID0gIkNDIiwgCiAgcEFkanVzdE1ldGhvZCA9ICJCSCIsCiAgcXZhbHVlQ3V0b2ZmICA9IDAuMDUKKQpgYGAKCmBgYHtyfQpwMSA8LSBkb3RwbG90KEdPX2VucmljaF91cDE2X0NDLCBzaG93Q2F0ZWdvcnkgPSAyMCkgKyAKICBnZ3RpdGxlKCI2Q2VsbHVsYXIgQ29tcG9uZW50IGZvciBVcHJlZ3VsYXRlZCBUYXJnZXRzIGluIFZlc2ljbGVzIDE2IikgKyAKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikKICApCgpwMiA8LSBkb3RwbG90KEdPX2VucmljaF9kb3duMTZfQ0MsIHNob3dDYXRlZ29yeSA9IDIwKSArIAogIGdndGl0bGUoIkNlbGx1bGFyIENvbXBvbmVudCBmb3IgRG93bnJlZ3VsYXRlZCBUYXJnZXRzIGluIFZlc2ljbGVzIDE2IikgKyAKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikKICApCgpwMSArIHAyCgpjb21iaW5lZF9wbG90IDwtIHAxICsgcDIKZ2dzYXZlKCIuL3BpY3R1cmVzL0dPX2VucmljaG1lbnRfZG90cGxvdF9DQ190eXBlMTYudGlmZiIsIHBsb3QgPSBjb21iaW5lZF9wbG90LCB3aWR0aCA9IDE2LCBoZWlnaHQgPSAxMCwgZHBpID0gMzAwKQpgYGAKYGBge3J9CkdPX2VucmljaF9VUDE2X0NDIDwtIGVucmljaHBsb3Q6OnBhaXJ3aXNlX3Rlcm1zaW0oR09fZW5yaWNoX3VwMTZfQ0MsIG1ldGhvZCA9ICJKQyIpCgpwbHQgPC0gZW1hcHBsb3QoR09fZW5yaWNoX1VQMTZfQ0MsIAogICAgICAgICByZXBlbCA9IFRSVUUsCiAgICAgICAgIHNob3dDYXRlZ29yeSA9IDIwKSArCiAgZ2d0aXRsZSgiQ2VsbHVsYXIgcHJvY2Vzc2VzIGZvciBVUHJlZ3VsYXRlZCB0YXJnZXRzIGZvciB2ZXNpY2xlcyAxNiIpICsKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSwKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMykKICAgICkgICAKCnBsdAoKZ2dzYXZlKCIuL3BpY3R1cmVzL0dPX2VucmljaG1lbnRfZW1hcHBsb3RfQ0NfdXBfdHlwZTE2LnRpZmYiLCBwbG90ID0gcGx0LCB3aWR0aCA9IDE2LCBoZWlnaHQgPSAxMCwgZHBpID0gMzAwKQpgYGAKYGBge3J9CkdPX2VucmljaF9ET1dOMTZfQ0MgPC0gZW5yaWNocGxvdDo6cGFpcndpc2VfdGVybXNpbShHT19lbnJpY2hfZG93bjE2X0NDLCBtZXRob2QgPSAiSkMiKQoKcGx0IDwtIGVtYXBwbG90KEdPX2VucmljaF9ET1dOMTZfQ0MsIAogICAgICAgICByZXBlbCA9IFRSVUUsCiAgICAgICAgIHNob3dDYXRlZ29yeSA9IDI1KSArCiAgZ2d0aXRsZSgiQ2VsbHVsYXIgcHJvY2Vzc2VzIGZvciBET1dOcmVndWxhdGVkIHRhcmdldHMgZm9yIHZlc2ljbGVzIDE2IikgKwogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpLAogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAzKQogICAgKSAgICAKCnBsdAoKZ2dzYXZlKCIuL3BpY3R1cmVzL0dPX2VucmljaG1lbnRfZW1hcHBsb3RfQ0NfZG93bl90eXBlMTYudGlmZiIsIHBsb3QgPSBwbHQsIHdpZHRoID0gMTYsIGhlaWdodCA9IDEwLCBkcGkgPSAzMDApCmBgYAoqKkdPIEVucmljaG1lbnQgb2YgTW9sZWN1bGFyIEZ1bmN0aW9uKioKYGBge3J9CkdPX2VucmljaF9kb3duMTZfTUYgPC0gZW5yaWNoR08oCiAgZ2VuZSAgICAgICAgICA9IHRhcmdldHMxNl9kb3duLCAgCiAgT3JnRGIgICAgICAgICA9IG9yZy5Icy5lZy5kYiwKICBrZXlUeXBlICAgICAgID0gIlNZTUJPTCIsCiAgb250ICAgICAgICAgICA9ICJNRiIsIAogIHBBZGp1c3RNZXRob2QgPSAiQkgiLAogIHF2YWx1ZUN1dG9mZiAgPSAwLjA1CikKCkdPX2VucmljaF91cDE2X01GIDwtIGVucmljaEdPKAogIGdlbmUgICAgICAgICAgPSB0YXJnZXRzMTZfdXAsICAKICBPcmdEYiAgICAgICAgID0gb3JnLkhzLmVnLmRiLAogIGtleVR5cGUgICAgICAgPSAiU1lNQk9MIiwKICBvbnQgICAgICAgICAgID0gIk1GIiwgCiAgcEFkanVzdE1ldGhvZCA9ICJCSCIsCiAgcXZhbHVlQ3V0b2ZmICA9IDAuMDUKKQoKcDEgPC0gZG90cGxvdChHT19lbnJpY2hfdXAxNl9NRiwgc2hvd0NhdGVnb3J5ID0gMjApICsgCiAgZ2d0aXRsZSgiTW9sZWN1bGFyIEZ1bmN0aW9uIGZvciBVcHJlZ3VsYXRlZCBUYXJnZXRzIGluIFZlc2ljbGVzIDE2IikgKyAKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikKICApCgpwMiA8LSBkb3RwbG90KEdPX2VucmljaF9kb3duMTZfTUYsIHNob3dDYXRlZ29yeSA9IDIwKSArIAogIGdndGl0bGUoIk1vbGVjdWxhciBGdW5jdGlvbnQgZm9yIERvd25yZWd1bGF0ZWQgVGFyZ2V0cyBpbiBWZXNpY2xlcyAxNiIpICsgCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpCiAgKQoKY29tYmluZWRfcGxvdCA8LSBwMSArIHAyCmNvbWJpbmVkX3Bsb3QKZ2dzYXZlKCIuL3BpY3R1cmVzL0dPX2VucmljaG1lbnRfZG90cGxvdF9NRl90eXBlMTYudGlmZiIsIHBsb3QgPSBjb21iaW5lZF9wbG90LCB3aWR0aCA9IDE2LCBoZWlnaHQgPSAxMCwgZHBpID0gMzAwKQpgYGAKYGBge3J9CkdPX2VucmljaF9VUDE2X01GIDwtIGVucmljaHBsb3Q6OnBhaXJ3aXNlX3Rlcm1zaW0oR09fZW5yaWNoX3VwMTZfTUYsIG1ldGhvZCA9ICJKQyIpCgpwbHQgPC0gZW1hcHBsb3QoR09fZW5yaWNoX1VQMTZfTUYsIAogICAgICAgICByZXBlbCA9IFRSVUUsCiAgICAgICAgIHNob3dDYXRlZ29yeSA9IDI1KSArCiAgZ2d0aXRsZSgiTW9sZWN1bGFyIEZ1bmN0aW9uIHByb2Nlc3NlcyBmb3IgVVByZWd1bGF0ZWQgdGFyZ2V0cyBmb3IgdmVzaWNsZXMgMTYiKSArCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDMpCiAgICApICAgCgpwbHQKCmdnc2F2ZSgiLi9waWN0dXJlcy9HT19lbnJpY2htZW50X2VtYXBwbG90X01GX3VwX3R5cGUxNi50aWZmIiwgcGxvdCA9IHBsdCwgd2lkdGggPSAxNiwgaGVpZ2h0ID0gMTAsIGRwaSA9IDMwMCkKYGBgCmBgYHtyfQpHT19lbnJpY2hfRE9XTjE2X01GIDwtIGVucmljaHBsb3Q6OnBhaXJ3aXNlX3Rlcm1zaW0oR09fZW5yaWNoX2Rvd24xNl9NRiwgbWV0aG9kID0gIkpDIikKCnBsdCA8LSBlbWFwcGxvdChHT19lbnJpY2hfRE9XTjE2X01GLCAKICAgICAgICAgcmVwZWwgPSBUUlVFLAogICAgICAgICBzaG93Q2F0ZWdvcnkgPSAyNSkgKwogIGdndGl0bGUoIk1vbGVjdWxhciBGdW5jdGlvbiBwcm9jZXNzZXMgZm9yIERPV05yZWd1bGF0ZWQgdGFyZ2V0cyBmb3IgdmVzaWNsZXMgMTYiKSArCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDMpCiAgICApICAgCgpwbHQKCmdnc2F2ZSgiLi9waWN0dXJlcy9HT19lbnJpY2htZW50X2VtYXBwbG90X01GX2Rvd25fdHlwZTE2LnRpZmYiLCBwbG90ID0gcGx0LCB3aWR0aCA9IDE2LCBoZWlnaHQgPSAxMCwgZHBpID0gMzAwKQpgYGAKCgoKCg==